Java tutorial
/** * Copyright (C) 2007 Asterios Raptis * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.sourceforge.jaulp.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 net.sourceforge.jaulp.file.FileExtension; import net.sourceforge.jaulp.file.namefilter.ResourceBundleFilenameFilter; import org.apache.commons.io.FilenameUtils; // TODO: Auto-generated Javadoc /** * 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()); /** * Private constructor. */ private PropertiesUtils() { } /** * 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(String propertyValue) { List<String> parameterList = new ArrayList<>(); Pattern pattern = Pattern.compile("\\{.*?\\}"); Matcher matcher = pattern.matcher(propertyValue); while (matcher.find()) { String parameter = matcher.group(); String at = parameter.substring(1, parameter.length() - 1); parameterList.add(at); } return parameterList; } /** * 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(Properties enProperties) { Enumeration<?> e = enProperties.propertyNames(); Map<String, List<String>> matchedPrefixes = new LinkedHashMap<>(); while (e.hasMoreElements()) { String key = (String) e.nextElement(); int lastIndex = key.lastIndexOf("."); String subKey = null; if (0 < lastIndex) { subKey = key.substring(0, lastIndex); } else { subKey = key; } if (matchedPrefixes.containsKey(subKey)) { List<String> fullKeys = matchedPrefixes.get(subKey); fullKeys.add(key); } else { List<String> fullKeys = new ArrayList<>(); fullKeys.add(key); matchedPrefixes.put(subKey, fullKeys); } } return matchedPrefixes; } /** * 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, 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; } /** * 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 = ClassUtils.getResource(packagePath); if (url != null) { properties = new Properties(); properties.load(url.openStream()); } else { InputStream is = ClassUtils.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); 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 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; } /** * 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(Class<?> clazz, final String name) throws IOException { Properties properties = loadProperties(name); if (properties == null) { final InputStream is = ClassUtils.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(Class<?> clazz, final String packagePath, String fileName) throws IOException { return loadProperties(clazz, 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(Class<?> clazz, 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; String packagePath = PackageUtils.getPackagePathWithSlash(clazz); List<String> missedFiles = new ArrayList<>(); if (null != locale) { propertiesName.append(clazz.getSimpleName()); language = locale.getLanguage(); if (null != language && !language.isEmpty()) { propertiesName.append("_").append(language); } 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 = ClassUtils.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 = ClassUtils.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; URL url = ClassUtils.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 (String string : missedFiles) { LOGGER.info(string); } } return properties; } /** * 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(File properties, File xml, String comment, 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(InputStream properties, OutputStream xml, String comment, String encoding) throws FileNotFoundException, IOException { Properties prop = new Properties(); prop.load(properties); prop.storeToXML(xml, comment, encoding); } /** * 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(File properties, File xml, 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(OutputStream properties, InputStream xml, String comment) throws FileNotFoundException, IOException { Properties prop = new Properties(); prop.loadFromXML(xml); prop.store(properties, comment); } /** * 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(Properties properties) { Map<String, List<String>> reverseEntries = new LinkedHashMap<>(); for (Map.Entry<Object, Object> entry : properties.entrySet()) { String key = (String) entry.getKey(); String value = (String) entry.getValue(); if (!reverseEntries.containsKey(value)) { List<String> keys = new ArrayList<>(); keys.add(key); reverseEntries.put(value, keys); } else { List<String> keys = reverseEntries.get(value); keys.add(key); } } Map<String, List<String>> redundantValues = new LinkedHashMap<>(); for (Map.Entry<String, List<String>> entry : reverseEntries.entrySet()) { String key = entry.getKey(); 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(String bundlepackage, final String bundlename) { ClassLoader loader = Thread.currentThread().getContextClassLoader(); File root = new File(loader.getResource(bundlepackage.replace('.', '/')).getFile()); File[] files = root.listFiles(new ResourceBundleFilenameFilter(bundlename)); Set<String> languages = new TreeSet<>(); for (File file : files) { languages.add(file.getName().replaceAll("^" + bundlename + "(_)?|\\.properties$", "")); } return languages; } /** * 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(String bundlepackage, final String bundlename) { ClassLoader loader = Thread.currentThread().getContextClassLoader(); File root = new File(loader.getResource(bundlepackage.replace('.', '/')).getFile()); File[] files = root.listFiles(new ResourceBundleFilenameFilter(bundlename)); Map<File, Locale> locales = new HashMap<>(); for (File file : files) { Locale current = getLocale(file); locales.put(file, current); } return locales; } /** * Gets from the given properties file the locale. * * @param propertiesFile * the properties file * @return the locale */ public static Locale getLocale(File propertiesFile) { String localeString = propertiesFile.getName() .replaceAll("^" + getBundlename(propertiesFile) + "(_)?|\\.properties$", ""); Locale current = null; if (localeString != null && !localeString.isEmpty()) { 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 the bundle name from the given properties file. * * @param propertiesFile * the properties file * @return the bundle name */ public static String getBundlename(File propertiesFile) { String filename = propertiesFile.getName(); int indexOfUnderscore = filename.indexOf("_"); String bundlename = filename; if (0 < indexOfUnderscore) { bundlename = propertiesFile.getName().substring(0, filename.indexOf("_")); } return bundlename; } }