001/** 002 * Copyright 2010-2014 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.common.util.spring.env; 017 018import static com.google.common.base.Preconditions.checkNotNull; 019 020import java.util.Map; 021import java.util.Properties; 022import java.util.Set; 023 024import org.kuali.common.util.PropertyUtils; 025import org.kuali.common.util.log.LoggerUtils; 026import org.slf4j.Logger; 027import org.springframework.core.env.MapPropertySource; 028 029import com.google.common.collect.ImmutableSet; 030import com.google.common.collect.Maps; 031 032/** 033 * <p> 034 * 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 035 * might be represented as an environment variable. All of the aliases are then also checked. 036 * </p> 037 * 038 * <pre> 039 * foo.barBaz -> env.FOO_BAR_BAZ 040 * FOO_BAR_BAZ 041 * env.foo_bar_baz 042 * foo_bar_baz 043 * </pre> 044 */ 045public class SysEnvPropertySource extends MapPropertySource { 046 047 private static final Map<String, ImmutableSet<String>> ALIAS_CACHE = Maps.newConcurrentMap(); 048 private static final String GLOBAL_PROPERTIES_PROPERTY_SOURCE_NAME = "systemPropertiesAndEnvironmentVariables"; 049 private static final Logger logger = LoggerUtils.make(); 050 051 public SysEnvPropertySource() { 052 this(GLOBAL_PROPERTIES_PROPERTY_SOURCE_NAME, PropertyUtils.getGlobalProperties()); 053 } 054 055 public SysEnvPropertySource(String name, Properties source) { 056 this(name, convert(source)); 057 } 058 059 public SysEnvPropertySource(String name, Map<String, Object> source) { 060 super(name, source); 061 } 062 063 /** 064 * {@inheritDoc} 065 */ 066 @Override 067 public Object getProperty(String name) { 068 checkNotNull(name, "'name' cannot be null"); 069 Object value = super.getProperty(name); 070 if (value != null) { 071 return value; 072 } else { 073 Set<String> aliases = getAliases(name); 074 return getProperty(aliases, name); 075 } 076 } 077 078 protected Object getProperty(Set<String> aliases, String original) { 079 for (String alias : aliases) { 080 Object value = super.getProperty(alias); 081 if (value != null) { 082 logger.debug(String.format("PropertySource [%s] does not contain '%s', but found equivalent '%s'", this.getName(), original, alias)); 083 return value; 084 } 085 } 086 return null; 087 } 088 089 /** 090 * <pre> 091 * foo.barBaz -> env.FOO_BAR_BAZ 092 * FOO_BAR_BAZ 093 * env.foo_bar_baz 094 * foo_bar_baz 095 * </pre> 096 */ 097 protected ImmutableSet<String> getAliases(String name) { 098 ImmutableSet<String> aliases = ALIAS_CACHE.get(name); 099 if (aliases == null) { 100 // foo.barBaz -> env.FOO_BAR_BAZ 101 String env1 = EnvUtils.getEnvironmentVariableKey(name); 102 // foo.barBaz -> FOO_BAR_BAZ 103 String env2 = EnvUtils.toUnderscore(name).toUpperCase(); 104 // foo.barBaz -> env.foo_bar_baz 105 String env3 = env1.toLowerCase(); 106 // foo.barBaz -> foo_bar_baz 107 String env4 = env2.toLowerCase(); 108 aliases = ImmutableSet.of(env1, env2, env3, env4); 109 ALIAS_CACHE.put(name, aliases); 110 } 111 return aliases; 112 } 113 114 protected static Map<String, Object> convert(Properties properties) { 115 Map<String, Object> map = Maps.newHashMap(); 116 for (String key : properties.stringPropertyNames()) { 117 map.put(key, properties.getProperty(key)); 118 } 119 return map; 120 } 121 122 public void clearAliasCache() { 123 ALIAS_CACHE.clear(); 124 } 125 126}