8 changed files with 289 additions and 3 deletions
@ -0,0 +1,109 @@
@@ -0,0 +1,109 @@
|
||||
/* |
||||
* Copyright 2012-2020 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 |
||||
* |
||||
* https://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.springframework.cloud.util.random; |
||||
|
||||
import java.util.Map; |
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
|
||||
import org.springframework.boot.env.RandomValuePropertySource; |
||||
import org.springframework.core.env.PropertySource; |
||||
import org.springframework.util.StringUtils; |
||||
|
||||
/** |
||||
* @author Ryan Baxter |
||||
*/ |
||||
public class CachedRandomPropertySource |
||||
extends PropertySource<RandomValuePropertySource> { |
||||
|
||||
private static final String NAME = "cachedrandom"; |
||||
|
||||
private static final String PREFIX = NAME + "."; |
||||
|
||||
private static Map<String, Map<String, Object>> cache = new ConcurrentHashMap<>(); |
||||
|
||||
public CachedRandomPropertySource( |
||||
RandomValuePropertySource randomValuePropertySource) { |
||||
super(NAME, randomValuePropertySource); |
||||
|
||||
} |
||||
|
||||
CachedRandomPropertySource(RandomValuePropertySource randomValuePropertySource, |
||||
Map<String, Map<String, Object>> cache) { |
||||
super(NAME, randomValuePropertySource); |
||||
this.cache = cache; |
||||
} |
||||
|
||||
@Override |
||||
public Object getProperty(String name) { |
||||
if (!name.startsWith(PREFIX) || name.length() == PREFIX.length()) { |
||||
return null; |
||||
} |
||||
else { |
||||
if (logger.isTraceEnabled()) { |
||||
logger.trace("Generating random property for '" + name + "'"); |
||||
} |
||||
// TO avoid any weirdness from the type or key including a "." we look for the
|
||||
// last "." and substring everything instead of splitting on the "."
|
||||
String keyAndType = name.substring(PREFIX.length()); |
||||
int lastIndexOfDot = keyAndType.lastIndexOf("."); |
||||
if (lastIndexOfDot < 0) { |
||||
return null; |
||||
} |
||||
String key = keyAndType.substring(0, lastIndexOfDot); |
||||
String type = keyAndType.substring(lastIndexOfDot + 1); |
||||
if (StringUtils.hasText(key) && StringUtils.hasText(type)) { |
||||
return getRandom(type, key); |
||||
} |
||||
else { |
||||
return null; |
||||
} |
||||
} |
||||
} |
||||
|
||||
private Object getRandom(String type, String key) { |
||||
Map<String, Object> randomValueCache = getCacheForKey(key); |
||||
if (logger.isDebugEnabled()) { |
||||
logger.debug("Looking in random cache for key " + key + " with type " + type); |
||||
} |
||||
return randomValueCache.computeIfAbsent(type, (theType) -> { |
||||
if (logger.isDebugEnabled()) { |
||||
logger.debug( |
||||
"No random value found in cache for key and value, generating a new value"); |
||||
} |
||||
return getSource().getProperty("random." + type); |
||||
}); |
||||
} |
||||
|
||||
private Map<String, Object> getCacheForKey(String key) { |
||||
if (logger.isDebugEnabled()) { |
||||
logger.debug("Looking in random cache for key: " + key); |
||||
} |
||||
return cache.computeIfAbsent(key, theKey -> { |
||||
if (logger.isDebugEnabled()) { |
||||
logger.debug("No cached value found for key: " + key); |
||||
} |
||||
return new ConcurrentHashMap<>(); |
||||
}); |
||||
} |
||||
|
||||
public static void clearCache() { |
||||
if (cache != null) { |
||||
cache.clear(); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,48 @@
@@ -0,0 +1,48 @@
|
||||
/* |
||||
* Copyright 2012-2020 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 |
||||
* |
||||
* https://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.springframework.cloud.util.random; |
||||
|
||||
import javax.annotation.PostConstruct; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.boot.env.RandomValuePropertySource; |
||||
import org.springframework.context.annotation.Configuration; |
||||
import org.springframework.core.env.ConfigurableEnvironment; |
||||
import org.springframework.core.env.MutablePropertySources; |
||||
import org.springframework.core.env.PropertySource; |
||||
|
||||
/** |
||||
* @author Ryan Baxter |
||||
*/ |
||||
@Configuration(proxyBeanMethods = false) |
||||
public class CachedRandomPropertySourceAutoConfiguration { |
||||
|
||||
@Autowired |
||||
ConfigurableEnvironment environment; |
||||
|
||||
@PostConstruct |
||||
public void initialize() { |
||||
MutablePropertySources propertySources = environment.getPropertySources(); |
||||
PropertySource propertySource = propertySources |
||||
.get(RandomValuePropertySource.RANDOM_PROPERTY_SOURCE_NAME); |
||||
if (propertySource != null) { |
||||
propertySources.addLast(new CachedRandomPropertySource( |
||||
RandomValuePropertySource.class.cast(propertySource))); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,79 @@
@@ -0,0 +1,79 @@
|
||||
/* |
||||
* Copyright 2012-2020 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 |
||||
* |
||||
* https://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.springframework.cloud.util.random; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
import java.util.function.Function; |
||||
|
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
import org.mockito.Mock; |
||||
import org.mockito.junit.MockitoJUnitRunner; |
||||
|
||||
import org.springframework.boot.env.RandomValuePropertySource; |
||||
import org.springframework.test.annotation.DirtiesContext; |
||||
|
||||
import static org.assertj.core.api.BDDAssertions.then; |
||||
import static org.mockito.ArgumentMatchers.eq; |
||||
import static org.mockito.ArgumentMatchers.isA; |
||||
import static org.mockito.Mockito.spy; |
||||
import static org.mockito.Mockito.times; |
||||
import static org.mockito.Mockito.verify; |
||||
import static org.mockito.Mockito.when; |
||||
|
||||
/** |
||||
* @author Ryan Baxter |
||||
*/ |
||||
@RunWith(MockitoJUnitRunner.class) |
||||
@DirtiesContext |
||||
public class CachedRandomPropertySourceTests { |
||||
|
||||
@Mock |
||||
RandomValuePropertySource randomValuePropertySource; |
||||
|
||||
@Before |
||||
public void setup() { |
||||
|
||||
when(randomValuePropertySource.getProperty(eq("random.long"))) |
||||
.thenReturn(new Long(1234)); |
||||
} |
||||
|
||||
@Test |
||||
public void getProperty() { |
||||
Map<String, Map<String, Object>> cache = new HashMap<>(); |
||||
Map<String, Object> typeCache = new HashMap<>(); |
||||
typeCache.put("long", new Long(5678)); |
||||
Map<String, Object> spyedTypeCache = spy(typeCache); |
||||
cache.put("foo", spyedTypeCache); |
||||
Map<String, Map<String, Object>> spyedCache = spy(cache); |
||||
|
||||
CachedRandomPropertySource cachedRandomPropertySource = new CachedRandomPropertySource( |
||||
randomValuePropertySource, spyedCache); |
||||
then(cachedRandomPropertySource.getProperty("foo.app.long")).isNull(); |
||||
then(cachedRandomPropertySource.getProperty("cachedrandom.app")).isNull(); |
||||
|
||||
then(cachedRandomPropertySource.getProperty("cachedrandom.app.long")) |
||||
.isEqualTo(new Long(1234)); |
||||
then(cachedRandomPropertySource.getProperty("cachedrandom.foo.long")) |
||||
.isEqualTo(new Long(5678)); |
||||
verify(spyedCache, times(1)).computeIfAbsent(eq("app"), isA(Function.class)); |
||||
verify(spyedTypeCache, times(1)).computeIfAbsent(eq("long"), isA(Function.class)); |
||||
} |
||||
|
||||
} |
@ -1,7 +1,8 @@
@@ -1,7 +1,8 @@
|
||||
# Bootstrap components |
||||
org.springframework.cloud.bootstrap.BootstrapConfiguration=\ |
||||
org.springframework.cloud.bootstrap.TestBootstrapConfiguration,\ |
||||
org.springframework.cloud.bootstrap.TestHigherPriorityBootstrapConfiguration |
||||
org.springframework.cloud.bootstrap.TestHigherPriorityBootstrapConfiguration,\ |
||||
org.springframework.cloud.util.random.CachedRandomPropertySourceAutoConfiguration |
||||
|
||||
|
||||
org.springframework.boot.env.EnvironmentPostProcessor=\ |
||||
|
Loading…
Reference in new issue