de.alpharogroup.lang.PropertiesUtils.java Source code

Java tutorial

Introduction

Here is the source code for de.alpharogroup.lang.PropertiesUtils.java

Source

/**
 * The MIT License
 *
 * Copyright (C) 2007 Asterios Raptis
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
package de.alpharogroup.lang;

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.OutputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.io.FilenameUtils;

import de.alpharogroup.file.FileExtension;
import de.alpharogroup.file.namefilter.ResourceBundleFilenameFilter;

/**
 * The Class PropertiesUtils provides methods loading properties and other related operations for
 * properties like find redundant values or getting all available languages from a bundle.
 */
public final class PropertiesUtils {

    /**
     * The Constant SEARCH_FILE_PATTERN is a regex for searching java and html files.
     */
    public static final String SEARCH_FILE_PATTERN = "([^\\s]+(\\.(?i)(java|html|htm))$)";
    /**
     * The Constant PROPERTIES_DELIMITERS contains all valid delimiters for properties files.
     */
    public static final String[] PROPERTIES_DELIMITERS = { "=", ":", " " };

    /** The LOGGER. */
    private static final Logger LOGGER = Logger.getLogger(PropertiesUtils.class.getName());

    /**
     * Finds redundant values from the given Properties object and saves it to a Map.
     * 
     * @param properties
     *            The Properties to check.
     * @return A map that contains the redundant value as the key of the map and a List(as value of
     *         the map) of keys that have the redundant value.
     */
    public static Map<String, List<String>> findRedundantValues(final Properties properties) {
        final Map<String, List<String>> reverseEntries = new LinkedHashMap<>();
        for (final Map.Entry<Object, Object> entry : properties.entrySet()) {
            final String key = (String) entry.getKey();
            final String value = (String) entry.getValue();
            if (!reverseEntries.containsKey(value)) {
                final List<String> keys = new ArrayList<>();
                keys.add(key);
                reverseEntries.put(value, keys);
            } else {
                final List<String> keys = reverseEntries.get(value);
                keys.add(key);
            }
        }
        final Map<String, List<String>> redundantValues = new LinkedHashMap<>();
        for (final Map.Entry<String, List<String>> entry : reverseEntries.entrySet()) {
            final String key = entry.getKey();
            final List<String> keys = entry.getValue();
            if (1 < keys.size()) {
                redundantValues.put(key, keys);
            }
        }
        return redundantValues;
    }

    /**
     * Gets all the available languages to the given resource bundle name in the given bundle
     * package.
     * 
     * @param bundlepackage
     *            The package that contains the properties files.
     * @param bundlename
     *            The name of the resource bundle.
     * @return a Set of String objects with the available languages.
     */

    public static Set<String> getAvailableLanguages(final String bundlepackage, final String bundlename) {
        final ClassLoader loader = Thread.currentThread().getContextClassLoader();
        final File root = new File(loader.getResource(bundlepackage.replace('.', '/')).getFile());
        final File[] files = root.listFiles(new ResourceBundleFilenameFilter(bundlename));

        final Set<String> languages = new TreeSet<>();
        for (final File file : files) {
            languages.add(file.getName().replaceAll("^" + bundlename + "(_)?|\\.properties$", ""));
        }
        return languages;
    }

    /**
     * Gets the bundle name from the given properties file.
     * 
     * @param propertiesFile
     *            the properties file
     * @return the bundle name
     */
    public static String getBundlename(final File propertiesFile) {
        final String filename = propertiesFile.getName();
        final int indexOfUnderscore = filename.indexOf("_");
        String bundlename = filename;
        if (0 < indexOfUnderscore) {
            bundlename = propertiesFile.getName().substring(0, filename.indexOf("_"));
        }
        return bundlename;
    }

    /**
     * Gets from the given properties file the locale.
     * 
     * @param propertiesFile
     *            the properties file
     * @return the locale
     */
    public static Locale getLocale(final File propertiesFile) {
        final String localeString = propertiesFile.getName()
                .replaceAll("^" + getBundlename(propertiesFile) + "(_)?|\\.properties$", "");
        Locale current = null;
        if (localeString != null && !localeString.isEmpty()) {
            final String[] splitted = localeString.split("_");
            if (1 < splitted.length) {
                current = new Locale(splitted[0], splitted[1]);
            } else {
                current = new Locale(localeString);
            }
        } else {
            current = Locale.getDefault();
        }
        return current;
    }

    /**
     * Gets all the available Locales to the given resource bundle name in the given bundle package.
     * For now it is only for properties files.
     * 
     * @param bundlepackage
     *            The package that contains the properties files.
     * @param bundlename
     *            The name of the resource bundle.
     * @return a Map of File objects with the corresponding Locales to it.
     */
    public static Map<File, Locale> getLocales(final String bundlepackage, final String bundlename) {
        final ClassLoader loader = Thread.currentThread().getContextClassLoader();
        final File root = new File(loader.getResource(bundlepackage.replace('.', '/')).getFile());
        final File[] files = root.listFiles(new ResourceBundleFilenameFilter(bundlename));
        final Map<File, Locale> locales = new HashMap<>();
        for (final File file : files) {
            final Locale current = getLocale(file);
            locales.put(file, current);
        }
        return locales;
    }

    /**
     * Gets the properties.
     * 
     * @param componentClass
     *            the component class
     * @param defaultClass
     *            the default class
     * @param locale
     *            the locale
     * @return the properties
     * @throws Exception
     *             the exception
     */
    public static Properties getLocalPropertiesFromClass(final Class<?> componentClass, final Class<?> defaultClass,
            final Locale locale) throws Exception {
        // Try to find the properties file and the resource
        Properties properties = null;
        if (componentClass != null) {
            properties = PropertiesUtils.loadPropertiesFromClassObject(componentClass, locale);
        } else {
            properties = PropertiesUtils.loadPropertiesFromClassObject(defaultClass, locale);
        }
        return properties;
    }

    /**
     * Finds all keys with the same key prefixes from the given Properties and saves them to a Map
     * with the prefix as a key and holds a List with the whole keys the starts with the same key
     * prefix.
     * 
     * @param enProperties
     *            the en properties
     * @return the matched prefix lists
     */
    public static Map<String, List<String>> getMatchedPrefixLists(final Properties enProperties) {
        final Enumeration<?> e = enProperties.propertyNames();
        final Map<String, List<String>> matchedPrefixes = new LinkedHashMap<>();
        while (e.hasMoreElements()) {
            final String key = (String) e.nextElement();
            final int lastIndex = key.lastIndexOf(".");
            String subKey = null;
            if (0 < lastIndex) {
                subKey = key.substring(0, lastIndex);
            } else {
                subKey = key;
            }
            if (matchedPrefixes.containsKey(subKey)) {
                final List<String> fullKeys = matchedPrefixes.get(subKey);
                fullKeys.add(key);
            } else {
                final List<String> fullKeys = new ArrayList<>();
                fullKeys.add(key);
                matchedPrefixes.put(subKey, fullKeys);
            }
        }
        return matchedPrefixes;
    }

    /**
     * Finds the property parameters from the given propertyValue.
     * 
     * @param propertyValue
     *            the property value
     * @return the property parameters as a list.
     */
    public static List<String> getPropertyParameters(final String propertyValue) {
        final List<String> parameterList = new ArrayList<>();
        final Pattern pattern = Pattern.compile("\\{.*?\\}");
        final Matcher matcher = pattern.matcher(propertyValue);
        while (matcher.find()) {
            final String parameter = matcher.group();
            final String at = parameter.substring(1, parameter.length() - 1);
            parameterList.add(at);
        }
        return parameterList;
    }

    /**
     * Load properties.
     * 
     * @param clazz
     *            the clazz
     * @param name
     *            the package path with the file name
     * @return the properties
     * @throws IOException
     *             Signals that an I/O exception has occurred.
     */
    public static Properties loadProperties(final Class<?> clazz, final String name) throws IOException {
        Properties properties = loadProperties(name);
        if (properties == null) {
            final InputStream is = ClassExtensions.getResourceAsStream(clazz.getClass(), name);
            if (is != null) {
                properties = new Properties();
                properties.load(is);
            }
        }
        return properties;
    }

    /**
     * Load properties.
     *
     * @param clazz
     *            the clazz
     * @param packagePath
     *            the package path without the file name
     * @param fileName
     *            the file name
     * @return the properties
     * @throws IOException
     *             Signals that an I/O exception has occurred.
     */
    public static Properties loadProperties(final Class<?> clazz, final String packagePath, final String fileName)
            throws IOException {
        return loadProperties(clazz, packagePath + fileName);
    }

    /**
     * Load a Properties-object from the given File-object.
     * 
     * @param propertiesFile
     *            the properties file
     * @return the properties or null if the file is not found.
     * @throws IOException
     *             Signals that an I/O exception has occurred.
     */
    public static Properties loadProperties(final File propertiesFile) throws IOException {
        Properties properties = null;
        InputStream is = null;
        if (propertiesFile.exists()) {
            is = propertiesFile.toURI().toURL().openStream();
            if (is != null) {
                properties = new Properties();
                properties.load(is);
            }
        } else {
            throw new FileNotFoundException(propertiesFile.getName() + " not found.");
        }
        return properties;
    }

    /**
     * Gives a Properties-object from the given packagepath.
     * 
     * @param packagePath
     *            The package-path and the name from the resource as a String.
     * @return The Properties-object from the given packagepath.
     * @throws IOException
     *             Signals that an I/O exception has occurred.
     */
    public static Properties loadProperties(final String packagePath) throws IOException {
        Properties properties = null;
        final URL url = ClassExtensions.getResource(packagePath);
        if (url != null) {
            properties = new Properties();
            properties.load(url.openStream());
        } else {
            final InputStream is = ClassExtensions.getResourceAsStream(packagePath);
            if (is != null) {
                properties = new Properties();
                properties.load(is);
            }
        }
        return properties;
    }

    /**
     * Load properties.
     *
     * @param packagePath
     *            the package path without the file name
     * @param fileName
     *            the file name
     * @return the properties
     * @throws IOException
     *             Signals that an I/O exception has occurred.
     */
    public static Properties loadProperties(String packagePath, String fileName) throws IOException {
        StringBuilder sb = new StringBuilder();
        packagePath = FilenameUtils.normalize(packagePath);
        final String slash = "/";
        if (packagePath.startsWith(slash)) {
            // remove first slash...
            if (packagePath.endsWith(slash)) {
                sb.append(packagePath.substring(1, packagePath.length()));
            } else {
                // append slash at the end...
                sb.append(packagePath.substring(1, packagePath.length())).append(slash);
            }
        } else {
            if (packagePath.endsWith(slash)) {
                // remove first char...
                sb.append(packagePath);
            } else {
                // remove first char...
                sb.append(packagePath).append(slash);
            }
        }
        packagePath = sb.toString().trim();
        sb = new StringBuilder();
        if (fileName.startsWith(slash)) {
            sb.append(fileName.substring(1, fileName.length()));
        }
        fileName = sb.toString().trim();
        return loadProperties(packagePath + fileName);
    }

    /**
     * Load the properties file from the given class object. The filename from the properties file
     * is the same as the simple name from the class object and it looks at the same path as the
     * given class object. If locale is not null than the language will be added to the filename
     * from the properties file.
     * 
     * @param clazz
     *            the clazz
     * @param locale
     *            the locale
     * @return the properties
     * @throws IOException
     *             Signals that an I/O exception has occurred.
     */
    public static Properties loadPropertiesFromClassObject(final Class<?> clazz, final Locale locale)
            throws IOException {
        if (null == clazz) {
            throw new IllegalArgumentException("Class object must not be null!!!");
        }
        StringBuilder propertiesName = new StringBuilder();
        Properties properties = null;
        String language = null;
        String filename = null;
        String pathAndFilename = null;
        File propertiesFile = null;
        String absoluteFilename = null;
        final String packagePath = PackageUtils.getPackagePathWithSlash(clazz);
        final List<String> missedFiles = new ArrayList<>();
        if (null != locale) {
            propertiesName.append(clazz.getSimpleName());
            language = locale.getLanguage();
            if (null != language && !language.isEmpty()) {
                propertiesName.append("_").append(language);
            }

            final String country = locale.getCountry();
            if (null != country && !country.isEmpty()) {
                propertiesName.append("_").append(country);
            }
            propertiesName.append(FileExtension.PROPERTIES.getExtension());
            filename = propertiesName.toString().trim();
            pathAndFilename = packagePath + filename;
            URL url = ClassExtensions.getResource(clazz, filename);

            if (url != null) {
                absoluteFilename = url.getFile();
            } else {
                missedFiles.add("File with filename '" + filename + "' does not exists.");
            }

            if (null != absoluteFilename) {
                propertiesFile = new File(absoluteFilename);
            }

            if (null != propertiesFile && propertiesFile.exists()) {
                properties = PropertiesUtils.loadProperties(pathAndFilename);
            } else {
                propertiesName = new StringBuilder();
                if (null != locale) {
                    propertiesName.append(clazz.getSimpleName());
                    language = locale.getLanguage();
                    if (null != language && !language.isEmpty()) {
                        propertiesName.append("_").append(language);
                    }
                    propertiesName.append(FileExtension.PROPERTIES.getExtension());
                    filename = propertiesName.toString().trim();
                    pathAndFilename = packagePath + filename;
                    url = ClassExtensions.getResource(clazz, filename);

                    if (url != null) {
                        absoluteFilename = url.getFile();
                    } else {
                        missedFiles.add("File with filename '" + filename + "' does not exists.");
                    }
                    if (null != absoluteFilename) {
                        propertiesFile = new File(absoluteFilename);
                    }
                    if (null != propertiesFile && propertiesFile.exists()) {
                        properties = PropertiesUtils.loadProperties(pathAndFilename);
                    }
                }
            }
        }

        if (null == properties) {
            propertiesName = new StringBuilder();
            propertiesName.append(clazz.getSimpleName()).append(FileExtension.PROPERTIES.getExtension());
            filename = propertiesName.toString().trim();
            pathAndFilename = packagePath + filename;
            final URL url = ClassExtensions.getResource(clazz, filename);

            if (url != null) {
                absoluteFilename = url.getFile();
            } else {
                properties = PropertiesUtils.loadProperties(pathAndFilename);
                missedFiles.add("File with filename '" + filename + "' does not exists.");
            }

            if (null != absoluteFilename) {
                propertiesFile = new File(absoluteFilename);
            }
            if (null != propertiesFile && propertiesFile.exists()) {
                properties = PropertiesUtils.loadProperties(pathAndFilename);
            }
        }
        if (properties == null) {
            for (final String string : missedFiles) {
                LOGGER.info(string);
            }
        }

        return properties;
    }

    /**
     * Converts the given xml file to the given properties file.
     * 
     * @param properties
     *            the properties file. The xml file does not have to exist.
     * @param xml
     *            the xml file with the properties to convert.
     * @param comment
     *            the comment
     * @throws FileNotFoundException
     *             the file not found exception
     * @throws IOException
     *             Signals that an I/O exception has occurred.
     */
    public static void toProperties(final File properties, final File xml, final String comment)
            throws FileNotFoundException, IOException {
        toProperties(new FileOutputStream(properties), new FileInputStream(xml), comment);
    }

    /**
     * Converts the given xml InputStream to the given properties OutputStream.
     * 
     * @param properties
     *            the properties file. The xml file does not have to exist.
     * @param xml
     *            the xml file with the properties to convert.
     * @param comment
     *            the comment
     * @throws FileNotFoundException
     *             the file not found exception
     * @throws IOException
     *             Signals that an I/O exception has occurred.
     */
    public static void toProperties(final OutputStream properties, final InputStream xml, final String comment)
            throws FileNotFoundException, IOException {
        final Properties prop = new Properties();
        prop.loadFromXML(xml);
        prop.store(properties, comment);
    }

    /**
     * Converts the given properties file to the given xml file.
     * 
     * @param properties
     *            the properties file.
     * @param xml
     *            the xml file to write in. The xml file does not have to exist.
     * @param comment
     *            the comment
     * @param encoding
     *            the encoding for the xml file.
     * @throws FileNotFoundException
     *             the file not found exception
     * @throws IOException
     *             Signals that an I/O exception has occurred.
     */
    public static void toXml(final File properties, final File xml, final String comment, final String encoding)
            throws FileNotFoundException, IOException {
        toXml(new FileInputStream(properties), new FileOutputStream(xml), comment, encoding);
    }

    /**
     * Converts the given properties InputStream to the given xml OutputStream.
     * 
     * @param properties
     *            the properties InputStream.
     * @param xml
     *            the xml OutputStream to write in.
     * @param comment
     *            the comment
     * @param encoding
     *            the encoding for the xml file.
     * @throws FileNotFoundException
     *             the file not found exception
     * @throws IOException
     *             Signals that an I/O exception has occurred.
     */
    public static void toXml(final InputStream properties, final OutputStream xml, final String comment,
            final String encoding) throws FileNotFoundException, IOException {
        final Properties prop = new Properties();
        prop.load(properties);
        prop.storeToXML(xml, comment, encoding);
    }

    /**
     * Private constructor.
     */
    private PropertiesUtils() {
    }

}