From 982f4fe8503c6b9fefbc62163a7d5cc76e66c513 Mon Sep 17 00:00:00 2001 From: John Blum Date: Thu, 31 May 2018 12:29:37 -0700 Subject: [PATCH] Cache constructed GemFire Mock Objects and destroy the 'disposable' objects properly at the end of test execution. --- .../tests/mock/GemFireMockObjectsSupport.java | 82 +++++++++++++------ 1 file changed, 58 insertions(+), 24 deletions(-) diff --git a/spring-test-data-geode/src/main/java/org/springframework/data/gemfire/tests/mock/GemFireMockObjectsSupport.java b/spring-test-data-geode/src/main/java/org/springframework/data/gemfire/tests/mock/GemFireMockObjectsSupport.java index 8cd4593..2278895 100644 --- a/spring-test-data-geode/src/main/java/org/springframework/data/gemfire/tests/mock/GemFireMockObjectsSupport.java +++ b/spring-test-data-geode/src/main/java/org/springframework/data/gemfire/tests/mock/GemFireMockObjectsSupport.java @@ -130,6 +130,7 @@ import org.apache.geode.pdx.PdxSerializer; import org.apache.lucene.analysis.Analyzer; import org.mockito.ArgumentMatchers; import org.mockito.stubbing.Answer; +import org.springframework.beans.factory.DisposableBean; import org.springframework.data.gemfire.IndexType; import org.springframework.data.gemfire.server.SubscriptionEvictionPolicy; import org.springframework.data.gemfire.tests.mock.support.MockObjectInvocationException; @@ -207,6 +208,8 @@ public abstract class GemFireMockObjectsSupport extends MockObjectsSupport { private static final AtomicReference singletonCache = new AtomicReference<>(null); private static final AtomicReference gemfireProperties = new AtomicReference<>(new Properties()); + private static final List cachedGemFireObjects = Collections.synchronizedList(new ArrayList<>()); + private static final Map diskStores = new ConcurrentHashMap<>(); private static final Map> regions = new ConcurrentHashMap<>(); @@ -231,11 +234,64 @@ public abstract class GemFireMockObjectsSupport extends MockObjectsSupport { * Destroys all mock object state. */ public static void destroy() { + singletonCache.set(null); gemfireProperties.set(new Properties()); diskStores.clear(); regions.clear(); regionAttributes.clear(); + + destroyGemFireObjects(); + } + + /** + * Destroys all {@link DisposableBean} based {@link Object GemFire objects}. + */ + private static void destroyGemFireObjects() { + + cachedGemFireObjects.stream() + .filter(gemfireObject -> gemfireObject instanceof DisposableBean) + .map(gemfireObject -> (DisposableBean) gemfireObject) + .forEach(disposableBean -> { + ObjectUtils.doOperationSafely(() -> { + disposableBean.destroy(); + return null; + }); + }); + + cachedGemFireObjects.clear(); + } + + /** + * Caches the given {@link Object GemFire object} in order to release resources on shutdown. + * + * @param gemfireObject {@link Object GemFire object} to cache. + */ + private static void cacheGemFireObject(Object gemfireObject) { + Optional.ofNullable(gemfireObject).ifPresent(cachedGemFireObjects::add); + } + + /** + * Instantiates all Apache Geode/Pivotal GemFire objects which have been declared + * via {@link System#getProperties() System properties}. + * + * @param {@link Class type} of the {@link GemFireCache}. + * @param gemfireCache reference to the {@link GemFireCache} instance. + * @return the given {@link GemFireCache} instance. + * @see org.apache.geode.cache.GemFireCache + */ + private static T constructGemFireObjects(T gemfireCache) { + + Properties localGemfireProperties = gemfireProperties.get(); + + Arrays.stream(GEMFIRE_OBJECT_BASED_PROPERTIES) + .map(localGemfireProperties::getProperty) + .filter(StringUtils::hasText) + .filter(className -> ClassUtils.isPresent(className, ClassUtils.getDefaultClassLoader())) + .forEach(className -> + cacheGemFireObject(ReflectionUtils.createInstanceIfPresent(className, null))); + + return gemfireCache; } /** @@ -321,28 +377,6 @@ public abstract class GemFireMockObjectsSupport extends MockObjectsSupport { }).orElse(DataPolicy.DEFAULT); } - /** - * Instantiates all Apache Geode/Pivotal GemFire objects which have been declared - * via {@link System#getProperties() System properties}. - * - * @param {@link Class type} of the {@link GemFireCache}. - * @param gemfireCache reference to the {@link GemFireCache} instance. - * @return the given {@link GemFireCache} instance. - * @see org.apache.geode.cache.GemFireCache - */ - private static T instantiateGemFireObjects(T gemfireCache) { - - Properties localGemfireProperties = gemfireProperties.get(); - - Arrays.stream(GEMFIRE_OBJECT_BASED_PROPERTIES) - .map(localGemfireProperties::getProperty) - .filter(StringUtils::hasText) - .filter(className -> ClassUtils.isPresent(className, ClassUtils.getDefaultClassLoader())) - .forEach(className -> ReflectionUtils.createInstanceIfPresent(className, null)); - - return gemfireCache; - } - /** * Determines whether the given {@link Region} is a root {@link Region}. * @@ -2663,7 +2697,7 @@ public abstract class GemFireMockObjectsSupport extends MockObjectsSupport { doAnswer(invocation -> { storeConfiguration(cacheFactory); - return rememberMockedGemFireCache(instantiateGemFireObjects(resolvedMockCache), useSingletonCache); + return rememberMockedGemFireCache(constructGemFireObjects(resolvedMockCache), useSingletonCache); }).when(cacheFactorySpy).create(); return cacheFactorySpy; @@ -2830,7 +2864,7 @@ public abstract class GemFireMockObjectsSupport extends MockObjectsSupport { doAnswer(invocation -> { storeConfiguration(clientCacheFactory); - return rememberMockedGemFireCache(instantiateGemFireObjects(resolvedMockedClientCache), useSingletonCache); + return rememberMockedGemFireCache(constructGemFireObjects(resolvedMockedClientCache), useSingletonCache); }).when(clientCacheFactorySpy).create(); return clientCacheFactorySpy;