001package org.kuali.common.util.spring.env; 002 003import static com.google.common.base.Preconditions.checkNotNull; 004 005import java.util.Map; 006import java.util.Properties; 007import java.util.Set; 008 009import org.kuali.common.util.PropertyUtils; 010import org.kuali.common.util.log.LoggerUtils; 011import org.slf4j.Logger; 012import org.springframework.core.env.MapPropertySource; 013 014import com.google.common.collect.ImmutableSet; 015import com.google.common.collect.Maps; 016 017/** 018 * <p> 019 * When {@code getProperty(name)} is called, {@code name} is checked. If no value is found, {@code name} is then converted into several aliases representing a few different ways it 020 * might be represented as an environment variable. All of the aliases are then also checked. 021 * </p> 022 * 023 * <pre> 024 * foo.barBaz -> env.FOO_BAR_BAZ 025 * FOO_BAR_BAZ 026 * env.foo_bar_baz 027 * foo_bar_baz 028 * </pre> 029 */ 030public class SysEnvPropertySource extends MapPropertySource { 031 032 private static final Map<String, ImmutableSet<String>> ALIAS_CACHE = Maps.newConcurrentMap(); 033 private static final String GLOBAL_PROPERTIES_PROPERTY_SOURCE_NAME = "systemPropertiesAndEnvironmentVariables"; 034 private static final Logger logger = LoggerUtils.make(); 035 036 public SysEnvPropertySource() { 037 this(GLOBAL_PROPERTIES_PROPERTY_SOURCE_NAME, PropertyUtils.getGlobalProperties()); 038 } 039 040 public SysEnvPropertySource(String name, Properties source) { 041 this(name, convert(source)); 042 } 043 044 public SysEnvPropertySource(String name, Map<String, Object> source) { 045 super(name, source); 046 } 047 048 /** 049 * {@inheritDoc} 050 */ 051 @Override 052 public Object getProperty(String name) { 053 checkNotNull(name, "'name' cannot be null"); 054 Object value = super.getProperty(name); 055 if (value != null) { 056 return value; 057 } else { 058 Set<String> aliases = getAliases(name); 059 return getProperty(aliases, name); 060 } 061 } 062 063 protected Object getProperty(Set<String> aliases, String original) { 064 for (String alias : aliases) { 065 Object value = super.getProperty(alias); 066 if (value != null) { 067 logger.debug(String.format("PropertySource [%s] does not contain '%s', but found equivalent '%s'", this.getName(), original, alias)); 068 return value; 069 } 070 } 071 return null; 072 } 073 074 /** 075 * <pre> 076 * foo.barBaz -> env.FOO_BAR_BAZ 077 * FOO_BAR_BAZ 078 * env.foo_bar_baz 079 * foo_bar_baz 080 * </pre> 081 */ 082 protected ImmutableSet<String> getAliases(String name) { 083 ImmutableSet<String> aliases = ALIAS_CACHE.get(name); 084 if (aliases == null) { 085 // foo.barBaz -> env.FOO_BAR_BAZ 086 String env1 = EnvUtils.getEnvironmentVariableKey(name); 087 // foo.barBaz -> FOO_BAR_BAZ 088 String env2 = EnvUtils.toUnderscore(name).toUpperCase(); 089 // foo.barBaz -> env.foo_bar_baz 090 String env3 = env1.toLowerCase(); 091 // foo.barBaz -> foo_bar_baz 092 String env4 = env2.toLowerCase(); 093 aliases = ImmutableSet.of(env1, env2, env3, env4); 094 ALIAS_CACHE.put(name, aliases); 095 } 096 return aliases; 097 } 098 099 protected static Map<String, Object> convert(Properties properties) { 100 Map<String, Object> map = Maps.newHashMap(); 101 for (String key : properties.stringPropertyNames()) { 102 map.put(key, properties.getProperty(key)); 103 } 104 return map; 105 } 106 107 public void clearAliasCache() { 108 ALIAS_CACHE.clear(); 109 } 110 111}