/* * Copyright 2004-2009 the original author or authors. * * 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 org.compass.core.config; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import org.compass.core.util.ClassUtils; /** * A set of settings that are used to configure the Compass instance. * * @author kimchy */ public class CompassSettings { private ConcurrentHashMap<String, Object> settings; private final Map<String, HashMap<String, CompassSettings>> groups = new ConcurrentHashMap<String, HashMap<String, CompassSettings>>(); private Map<Object, Object> registry = new ConcurrentHashMap<Object, Object>(); private ClassLoader classLoader; private CompassSettings gloablSettings; public CompassSettings() { this.settings = new ConcurrentHashMap<String, Object>(); } public CompassSettings(ClassLoader classLoader) { this(); this.classLoader = classLoader; } public CompassSettings(Map<String, Object> settings) { this(); this.settings.putAll(settings); } public void setGlobalSettings(CompassSettings settings) { this.gloablSettings = settings; } /** * Returns the global settings. Useful when getting group based settings and still access the global * settings that created it. */ public CompassSettings getGloablSettings() { if (gloablSettings == null) { return this; } return gloablSettings; } public void addSettings(Properties settings) { for (Map.Entry entry : settings.entrySet()) { setSetting((String) entry.getKey(), (String) entry.getValue()); } } public void addSettings(Map<String, Object> settings) { this.settings.putAll(settings); } public Map<String, Object> getUnderlyingMap() { return settings; } public Properties getProperties() { Properties properties = new Properties(); for (Map.Entry<String, Object> entry : settings.entrySet()) { if (entry.getValue() instanceof String) { properties.setProperty(entry.getKey(), (String) entry.getValue()); } } return properties; } public void addSettings(CompassSettings settings) { this.settings.putAll(settings.settings); this.registry.putAll(settings.registry); if (this.gloablSettings != null && settings.gloablSettings != null) { this.gloablSettings.addSettings(settings.gloablSettings); } } public CompassSettings copy() { CompassSettings copySettings = new CompassSettings(); copySettings.gloablSettings = gloablSettings; copySettings.settings.putAll(settings); copySettings.registry = new ConcurrentHashMap<Object, Object>(registry); copySettings.classLoader = classLoader; return copySettings; } public CompassSettings clear() { this.settings.clear(); return this; } void setClassLoader(ClassLoader classLoader) { this.classLoader = classLoader; } /** * Returns the class loader. If none is defined, return the thread context class loader. */ public ClassLoader getClassLoader() { if (classLoader == null) { return Thread.currentThread().getContextClassLoader(); } return classLoader; } /** * Returns the direct class loader configured for this settings. <code>null</code> * if none is defined. */ public ClassLoader getDirectClassLoader() { return this.classLoader; } public Collection keySet() { return settings.keySet(); } public void removeSetting(String setting) { settings.remove(setting); } public String getSetting(String setting) { return (String) settings.get(setting); } public Object getSettingAsObject(String setting) { return settings.get(setting); } public String getSetting(String setting, String defaultValue) { String retVal = (String) settings.get(setting); if (retVal == null) { return defaultValue; } return retVal; } public Map<String, CompassSettings> getSettingGroups(String settingPrefix) { if (settingPrefix.charAt(settingPrefix.length() - 1) != '.') { settingPrefix = settingPrefix + "."; } Map<String, CompassSettings> group = groups.get(settingPrefix); if (group != null) { return group; } // we don't really care that it might happen twice HashMap<String, CompassSettings> map = new HashMap<String, CompassSettings>(); for (Object o : settings.keySet()) { String setting = (String) o; if (setting.startsWith(settingPrefix)) { String nameValue = setting.substring(settingPrefix.length()); int dotIndex = nameValue.indexOf('.'); if (dotIndex == -1) { throw new ConfigurationException("Failed to get setting group for [" + settingPrefix + "] setting prefix and setting [" + setting + "] because of a missing '.'"); } String name = nameValue.substring(0, dotIndex); String value = nameValue.substring(dotIndex + 1); CompassSettings groupSettings = map.get(name); if (groupSettings == null) { groupSettings = new CompassSettings(); groupSettings.setGlobalSettings(getGloablSettings()); groupSettings.setClassLoader(getClassLoader()); map.put(name, groupSettings); } groupSettings.setObjectSetting(value, getSettingAsObject(setting)); } } groups.put(settingPrefix, map); return map; } public float getSettingAsFloat(String setting, float defaultValue) { String sValue = getSetting(setting); if (sValue == null) { return defaultValue; } return Float.parseFloat(sValue); } public double getSettingAsDouble(String setting, double defaultValue) { String sValue = getSetting(setting); if (sValue == null) { return defaultValue; } return Double.parseDouble(sValue); } public int getSettingAsInt(String setting, int defaultValue) { String sValue = getSetting(setting); if (sValue == null) { return defaultValue; } return Integer.parseInt(sValue); } public long getSettingAsLong(String setting, long defaultValue) { String sValue = getSetting(setting); if (sValue == null) { return defaultValue; } return Long.parseLong(sValue); } public boolean getSettingAsBoolean(String setting, boolean defaultValue) { String sValue = getSetting(setting); if (sValue == null) { return defaultValue; } return Boolean.valueOf(sValue); } public long getSettingAsTimeInSeconds(String setting, long defaultValue) { String sValue = getSetting(setting); if (sValue == null) { return defaultValue; } if (sValue.endsWith("S")) { throw new IllegalArgumentException("Expected time in seconds, does not support millis"); } else if (sValue.endsWith("millis")) { throw new IllegalArgumentException("Expected time in seconds, does not support millis"); } else if (sValue.endsWith("s")) { return (long) (Double.parseDouble(sValue.substring(0, sValue.length() - 1))); } else if (sValue.endsWith("m")) { return (long) (Double.parseDouble(sValue.substring(0, sValue.length() - 1)) * 60); } else if (sValue.endsWith("H")) { return (long) (Double.parseDouble(sValue.substring(0, sValue.length() - 1)) * 60 * 60); } return Long.parseLong(sValue); } public long getSettingAsTimeInMillis(String setting, long defaultValue) { String sValue = getSetting(setting); if (sValue == null) { return defaultValue; } if (sValue.endsWith("S")) { return Long.parseLong(sValue.substring(0, sValue.length() - 1)); } else if (sValue.endsWith("millis")) { return (long) (Double.parseDouble(sValue.substring(0, sValue.length() - "millis".length())) * 1000); } else if (sValue.endsWith("s")) { return (long) (Double.parseDouble(sValue.substring(0, sValue.length() - 1)) * 1000); } else if (sValue.endsWith("m")) { return (long) (Double.parseDouble(sValue.substring(0, sValue.length() - 1)) * 60 * 1000); } else if (sValue.endsWith("H")) { return (long) (Double.parseDouble(sValue.substring(0, sValue.length() - 1)) * 60 * 60 * 1000); } return Long.parseLong(sValue); } public long getSettingAsBytes(String setting, long defaultValue) { String sValue = getSetting(setting); if (sValue == null) { return defaultValue; } return parseStringAsBytes(sValue); } public static long parseStringAsBytes(String sValue) { if (sValue.endsWith("b")) { return Long.parseLong(sValue.substring(0, sValue.length() - 1)); } else if (sValue.endsWith("k") || sValue.endsWith("K")) { return (long) (Double.parseDouble(sValue.substring(0, sValue.length() - 1)) * 1024); } else if (sValue.endsWith("m") || sValue.endsWith("M")) { return (long) (Double.parseDouble(sValue.substring(0, sValue.length() - 1)) * 1024 * 1024); } else if (sValue.endsWith("g") || sValue.endsWith("G")) { return (long) (Double.parseDouble(sValue.substring(0, sValue.length() - 1)) * 1024 * 1024 * 1024); } else { return Long.parseLong(sValue); } } public Class getSettingAsClass(String setting, Class clazz) throws ClassNotFoundException { String sValue = getSetting(setting); if (sValue == null) { return clazz; } return ClassUtils.forName(sValue, getClassLoader()); } public Class getSettingAsClass(String setting, Class clazz, ClassLoader classLoader) throws ClassNotFoundException { String sValue = getSetting(setting); if (sValue == null) { return clazz; } return ClassUtils.forName(sValue, classLoader); } public Object getSettingAsInstance(String setting) { return getSettingAsInstance(setting, null); } public Object getSettingAsInstance(String setting, String defaultClass) { Object type = getSettingAsObject(setting); if (type == null) { if (defaultClass == null) { return null; } type = defaultClass; } Object instance; if (type instanceof String) { try { instance = ClassUtils.forName((String) type, getClassLoader()).newInstance(); } catch (Exception e) { throw new ConfigurationException("Failed to instantiate [" + type + "], please verify class type at setting [" + setting + "]", e); } } else { instance = type; } if (instance instanceof CompassConfigurable) { ((CompassConfigurable) instance).configure(this); } return instance; } public CompassSettings setSetting(String setting, String value) { if (value == null) { return this; } this.settings.put(setting, value); return this; } public CompassSettings setObjectSetting(String setting, Object value) { if (value == null) { return this; } this.settings.put(setting, value); return this; } public CompassSettings setBooleanSetting(String setting, boolean value) { setSetting(setting, String.valueOf(value)); return this; } public CompassSettings setFloatSetting(String setting, float value) { setSetting(setting, String.valueOf(value)); return this; } public CompassSettings setDoubleSetting(String setting, double value) { setSetting(setting, String.valueOf(value)); return this; } public CompassSettings setIntSetting(String setting, int value) { setSetting(setting, String.valueOf(value)); return this; } public CompassSettings setLongSetting(String setting, long value) { setSetting(setting, String.valueOf(value)); return this; } /** * Sets the given time setting based on the given time unit, converting it to milliseconds. */ public CompassSettings setTimeSetting(String setting, long value, TimeUnit timeUnit) { setLongSetting(setting, timeUnit.toMillis(value)); return this; } public CompassSettings setClassSetting(String setting, Class clazz) { setSetting(setting, clazz.getName()); return this; } /** * Sets a group of settings, sharing the same setting prefix. The provided * settings are appended to the settingPrefix, and the matching values are * set. * <p/> * The constructed setting is: settingPrefix + "." + groupName + "." + settings[i]. * * @param settingPrefix The prefix used for all settings * @param groupName The name of the setting group * @param settings The settings name appended to settingsPrefix + "." + groupName + "." * @param values The values of the settings matched against the settings parameters * @return This settings instance for method chaining */ public CompassSettings setGroupSettings(String settingPrefix, String groupName, String[] settings, Object[] values) { if (settings.length != values.length) { throw new IllegalArgumentException("The settings length must match the value length"); } for (int i = 0; i < settings.length; i++) { if (values[i] == null) { continue; } setObjectSetting(settingPrefix + "." + groupName + "." + settings[i], values[i]); } return this; } /** * ADANCE: An internal compass global registry */ public Object getRegistry(Object key) { return registry.get(key); } /** * ADVANCE: An internal compass global registry */ public void setRegistry(Object key, Object value) { registry.put(key, value); } /** * ADVANCE: An internal compass global registry */ public Object removeRegistry(Object key) { return registry.remove(key); } public String toString() { return settings.toString(); } }