package com.sap.pto.util.configuration; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.sap.pto.util.configuration.ConfigSectionParam.Type; public class ConfigUtil { private static final Logger confLogger = LoggerFactory.getLogger("audit.configuration"); private static final String TEMP_GROUP = "temp_runtime"; private static Map<String, Properties> allProperties = new HashMap<String, Properties>(); private static List<Fallback> fallbacks = Arrays.asList(Fallback.DB, Fallback.SYSTEM, Fallback.FILE); private static List<ConfigSection> configSections = new ArrayList<ConfigSection>(); private static ConfigAdapter dbAdapter; public enum Fallback { DB, FILE, SYSTEM } public static void setDBAdapter(ConfigAdapter dbAdapter) { ConfigUtil.dbAdapter = dbAdapter; } public synchronized static String getProperty(String group, String key) { Properties properties = getProperties(group); if (properties != null) { return properties.getProperty(key); } else { return null; } } public synchronized static Boolean getBooleanProperty(String group, String key) { return Boolean.parseBoolean(getProperty(group, key)); } public synchronized static int getIntProperty(String group, String key) { return Integer.parseInt(getProperty(group, key)); } public synchronized static Properties getProperties(String group) { // load properties on demand if (!allProperties.containsKey(group)) { for (Fallback fallback : fallbacks) { confLogger.info("Loading property group '" + group + "' from " + fallback.name()); Properties properties = new Properties(); switch (fallback) { case DB: properties = loadFromDatabase(group); break; case FILE: properties = loadFromPropertiesFile(group); break; case SYSTEM: properties = loadFromSystemProperties(group); break; default: // confLogger.info(" Unknown fallback: " + fallback); } confLogger.info(" " + properties.size() + " properties loaded"); saveProperties(group, properties); } } if (allProperties.containsKey(group)) { return allProperties.get(group); } else { return null; } } public static void setProperties(String group, Properties properties) { allProperties.put(group, properties); } public static void setProperty(String group, String key, String value) { Properties existing = allProperties.get(group); if (existing == null) { existing = getProperties(group); if (existing == null) { existing = new Properties(); } } existing.put(key, value); allProperties.put(group, existing); } private static Properties loadFromPropertiesFile(String group) { Properties properties = new Properties(); int fileCounter = 1; String file = group + ".properties"; InputStream stream = null; do { stream = Thread.currentThread().getContextClassLoader().getResourceAsStream(file); if (stream != null) { try { properties.load(stream); } catch (IOException e) { throw new RuntimeException("Failed to read configuration from resource at '" + file + "'.", e); } finally { IOUtils.closeQuietly(stream); } } fileCounter += 1; file = group + "." + fileCounter + ".properties"; } while (stream != null); return properties; } private static Properties loadFromSystemProperties(String group) { Properties groupProperties = new Properties(); Properties properties = System.getProperties(); String prefix = group + "."; for (String key : properties.stringPropertyNames()) { if (key.startsWith(prefix)) { String value = properties.getProperty(key); groupProperties.put(key.substring(prefix.length()), value); } } return groupProperties; } private static Properties loadFromDatabase(String group) { if (dbAdapter != null) { return dbAdapter.getByGroup(group); } else { confLogger.error("Cannot load configuration from database. DB Adapter is not set."); return new Properties(); } } private static void saveProperties(String group, Properties properties) { if (properties.size() == 0) { return; } if (allProperties.containsKey(group)) { Properties existingProperties = allProperties.get(group); // save only new ones to obey fallback chain for (String key : properties.stringPropertyNames()) { if (!existingProperties.containsKey(key)) { existingProperties.put(key, properties.getProperty(key)); } } } else { allProperties.put(group, properties); } } public static void setTempProperty(String key, String value) { Properties properties = new Properties(); if (allProperties.containsKey(TEMP_GROUP)) { properties = allProperties.get(TEMP_GROUP); } properties.put(key, value); allProperties.put(TEMP_GROUP, properties); } public static String getTempProperty(String key) { return getProperty(TEMP_GROUP, key); } public static List<Fallback> getFallbacks() { return fallbacks; } public static void setFallbacks(List<Fallback> newFallbacks) { fallbacks = newFallbacks; } public static void reload() { confLogger.info("Reloading configuration"); allProperties.clear(); } public static Map<String, Properties> getAllProperties() { return allProperties; } public static List<ConfigSection> getConfigSections() { return getConfigSections(false); } public static List<ConfigSection> getConfigSections(boolean fillCurrentValues) { for (ConfigSection section : configSections) { for (ConfigSectionParam param : section.getParameters()) { if (fillCurrentValues && !param.getType().equals(Type.PASSWORD)) { param.setCurrentValue(getProperty(section.getKey(), param.getKey())); } else { param.setCurrentValue(null); } } } return configSections; } public static void setConfigSections(List<ConfigSection> configSections) { ConfigUtil.configSections = configSections; } public static void addConfigSection(ConfigSection config) { configSections.add(config); } public static void clearConfigSections() { configSections.clear(); } /** * Saves the configuration into the database. */ public static boolean saveConfiguration(ConfigSection section) { if (dbAdapter == null) { confLogger.error("Cannot save configuration. DB Adapter is not set."); return false; } for (ConfigSectionParam param : section.getParameters()) { dbAdapter.save(section.getKey(), param.getKey(), param.getCurrentValue()); } return true; } }