From a795930817c3e349ae4f7d12c2956154a4059d50 Mon Sep 17 00:00:00 2001 From: John Blum Date: Tue, 9 Mar 2021 15:52:25 -0800 Subject: [PATCH] Creates an AbstractCacheFactoryBean class hierarchy. Create the org.springframework.data.gemfire.AbstractBasicCacheFactoryBean class. Create the org.springframework.data.gemfire.AbstractPdxConfigurableCacheFactoryBean class, extending AbstractBasicCacheFactoryBean. Refactor org.springframework.data.gemfire.CacheFactoryBean to (indirectly ) extend AbstractBasicCacheFactoryBean. Resolves gh-493. --- .../AbstractBasicCacheFactoryBean.java | 736 +++++++++++++++ ...stractPdxConfigurableCacheFactoryBean.java | 209 +++++ .../data/gemfire/CacheFactoryBean.java | 873 +++--------------- .../client/ClientCacheFactoryBean.java | 261 +++--- ...st.java => CacheFactoryBeanUnitTests.java} | 469 +++++----- ...a => ClientCacheFactoryBeanUnitTests.java} | 157 ++-- .../test/MockClientCacheFactoryBean.java | 2 +- 7 files changed, 1548 insertions(+), 1159 deletions(-) create mode 100644 spring-data-geode/src/main/java/org/springframework/data/gemfire/AbstractBasicCacheFactoryBean.java create mode 100644 spring-data-geode/src/main/java/org/springframework/data/gemfire/AbstractPdxConfigurableCacheFactoryBean.java rename spring-data-geode/src/test/java/org/springframework/data/gemfire/{CacheFactoryBeanTest.java => CacheFactoryBeanUnitTests.java} (65%) rename spring-data-geode/src/test/java/org/springframework/data/gemfire/client/{ClientCacheFactoryBeanTest.java => ClientCacheFactoryBeanUnitTests.java} (93%) diff --git a/spring-data-geode/src/main/java/org/springframework/data/gemfire/AbstractBasicCacheFactoryBean.java b/spring-data-geode/src/main/java/org/springframework/data/gemfire/AbstractBasicCacheFactoryBean.java new file mode 100644 index 00000000..6ed7028c --- /dev/null +++ b/spring-data-geode/src/main/java/org/springframework/data/gemfire/AbstractBasicCacheFactoryBean.java @@ -0,0 +1,736 @@ +/* + * Copyright 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.data.gemfire; + +import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException; +import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newRuntimeException; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Optional; +import java.util.Properties; + +import org.apache.geode.GemFireCheckedException; +import org.apache.geode.GemFireException; +import org.apache.geode.cache.Cache; +import org.apache.geode.cache.CacheFactory; +import org.apache.geode.cache.GemFireCache; +import org.apache.geode.cache.Region; +import org.apache.geode.cache.client.ClientCache; +import org.apache.geode.cache.client.ClientCacheFactory; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.Phased; +import org.springframework.core.io.Resource; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor; +import org.springframework.dao.support.PersistenceExceptionTranslator; +import org.springframework.data.gemfire.client.ClientCacheFactoryBean; +import org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer; +import org.springframework.data.gemfire.config.annotation.PeerCacheConfigurer; +import org.springframework.data.gemfire.support.AbstractFactoryBeanSupport; +import org.springframework.data.gemfire.support.GemfireBeanFactoryLocator; +import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; + +/** + * Abstract base class for {@link CacheFactoryBean} and {@link ClientCacheFactoryBean} classes + * used to create Apache Geode peer {@link Cache} and {@link ClientCache} instances, respectively. + * + * This class implements Spring's {@link PersistenceExceptionTranslator} interface and is auto-detected by Spring's + * {@link PersistenceExceptionTranslationPostProcessor} to enable AOP-based translation of native Apache Geode + * {@link RuntimeException RuntimeExceptions} to Spring's {@link DataAccessException} hierarchy. Therefore, + * the presence of this class automatically enables a {@link PersistenceExceptionTranslationPostProcessor} + * to translate Apache Geode {@link RuntimeException RuntimeExceptions} appropriately. + * + * Importantly, this class encapsulates configure applicable to tuning Apache Geode in response to JVM Heap memory. + * Since Apache Geode stores data in-memory, on the JVM Heap, it is important that Aapche Geode be tuned to monitor + * the JVM Heap and respond accordingly to memory pressure, by evicting data and issuing warnings when the JVM Heap + * reaches critical mass. + * + * @author John Blum + * @see java.io.File + * @see java.util.Properties + * @see org.apache.geode.cache.Cache + * @see org.apache.geode.cache.CacheFactory + * @see org.apache.geode.cache.GemFireCache + * @see org.apache.geode.cache.Region + * @see org.apache.geode.cache.client.ClientCache + * @see org.apache.geode.cache.client.ClientCacheFactory + * @see org.springframework.beans.factory.BeanFactory + * @see org.springframework.beans.factory.DisposableBean + * @see org.springframework.beans.factory.FactoryBean + * @see org.springframework.beans.factory.InitializingBean + * @see org.springframework.context.Phased + * @see org.springframework.core.io.Resource + * @see org.springframework.dao.DataAccessException + * @see org.springframework.dao.support.PersistenceExceptionTranslator + * @see org.springframework.data.gemfire.CacheFactoryBean + * @see org.springframework.data.gemfire.client.ClientCacheFactoryBean + * @see org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer + * @see org.springframework.data.gemfire.config.annotation.PeerCacheConfigurer + * @see org.springframework.data.gemfire.support.AbstractFactoryBeanSupport + * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator + * @since 2.5.0 + */ +public abstract class AbstractBasicCacheFactoryBean extends AbstractFactoryBeanSupport + implements DisposableBean, InitializingBean, PersistenceExceptionTranslator, Phased { + + private boolean close = true; + private boolean useBeanFactoryLocator = false; + + private int phase = -1; + + private Boolean copyOnRead; + + private CacheFactoryInitializer cacheFactoryInitializer; + + private Float criticalHeapPercentage; + private Float criticalOffHeapPercentage; + private Float evictionHeapPercentage; + private Float evictionOffHeapPercentage; + + private GemfireBeanFactoryLocator beanFactoryLocator; + + private GemFireCache cache; + + private Properties properties; + + private Resource cacheXml; + + /** + * Gets a reference to the configured {@link GemfireBeanFactoryLocator} used to resolve Spring bean references + * in Apache Geode native configuration metadata (e.g. {@literal cache.xml}). + * + * @param beanFactoryLocator reference to the configured {@link GemfireBeanFactoryLocator}. + * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator + */ + protected void setBeanFactoryLocator(@Nullable GemfireBeanFactoryLocator beanFactoryLocator) { + this.beanFactoryLocator = beanFactoryLocator; + } + + /** + * Returns a reference to the configured {@link GemfireBeanFactoryLocator} used to resolve Spring bean references + * in Apache Geode native configuration metadata (e.g. {@literal cache.xml}). + * + * @return a reference to the configured {@link GemfireBeanFactoryLocator}. + * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator + */ + public @Nullable GemfireBeanFactoryLocator getBeanFactoryLocator() { + return this.beanFactoryLocator; + } + + /** + * Sets a reference to the constructed, configured an initialized {@link GemFireCache} instance created by + * this cache {@link FactoryBean}. + * + * @param cache {@link GemFireCache} created by this {@link FactoryBean}. + * @see org.apache.geode.cache.GemFireCache + */ + protected void setCache(@Nullable GemFireCache cache) { + this.cache = cache; + } + + /** + * Returns a reference to the constructed, configured an initialized {@link GemFireCache} instance created by + * this cache {@link FactoryBean}. + * + * @return a reference to the {@link GemFireCache} created by this {@link FactoryBean}. + * @see org.apache.geode.cache.GemFireCache + */ + @SuppressWarnings("unchecked") + public @Nullable T getCache() { + return (T) this.cache; + } + + /** + * Set the {@link CacheFactoryInitializer} called by this {@link FactoryBean} to initialize the Apache Geode + * cache factory used to create the cache constructed by this {@link FactoryBean}. + * + * @param cacheFactoryInitializer {@link CacheFactoryInitializer} called to initialize the cache factory. + * @see org.springframework.data.gemfire.CacheFactoryBean.CacheFactoryInitializer + */ + @SuppressWarnings("rawtypes") + public void setCacheFactoryInitializer(@Nullable CacheFactoryInitializer cacheFactoryInitializer) { + this.cacheFactoryInitializer = cacheFactoryInitializer; + } + + /** + * Return the {@link CacheFactoryInitializer} called by this {@link FactoryBean} to initialize the Apache Geode + * cache factory used to create the cache constructed by this {@link FactoryBean}. + * + * @return the {@link CacheFactoryInitializer} called to initialize the cache factory. + * @see org.springframework.data.gemfire.CacheFactoryBean.CacheFactoryInitializer + */ + @SuppressWarnings("rawtypes") + public @Nullable CacheFactoryInitializer getCacheFactoryInitializer() { + return this.cacheFactoryInitializer; + } + + /** + * Sets a reference to an (optional) Apache Geode native {@literal cache.xml} {@link Resource}. + * + * @param cacheXml reference to an (optional) Apache Geode native {@literal cache.xml} {@link Resource}. + * @see org.springframework.core.io.Resource + */ + public void setCacheXml(@Nullable Resource cacheXml) { + this.cacheXml = cacheXml; + } + + /** + * Returns a reference to an (optional) Apache Geode native {@literal cache.xml} {@link Resource}. + * + * @return a reference to an (optional) Apache Geode native {@literal cache.xml} {@link Resource}. + * @see org.springframework.core.io.Resource + */ + public @Nullable Resource getCacheXml() { + return this.cacheXml; + } + + /** + * Determines whether the {@literal cache.xml} {@link File} is present. + * + * @return boolean value indicating whether a {@literal cache.xml} {@link File} is present. + * @see org.springframework.core.io.Resource#isFile() + * @see #getCacheXml() + */ + @SuppressWarnings("unused") + protected boolean isCacheXmlAvailable() { + + Resource cacheXml = getCacheXml(); + + return cacheXml != null && cacheXml.isFile(); + } + + /** + * Returns the Apache Geode native {@literal cache.xml} {@link Resource} as a {@link File}. + * + * @return the Apache Geode native {@literal cache.xml} {@link Resource} as a {@link File}. + * @throws IllegalStateException if the {@link Resource} is not a valid {@link File} in the file system + * or a general problem exists accessing or reading the {@link File}. + * @see org.springframework.core.io.Resource + * @see java.io.File + * @see #getCacheXml() + */ + @SuppressWarnings("unused") + protected File getCacheXmlFile() { + + try { + return getCacheXml().getFile(); + } + catch (Throwable cause) { + throw newIllegalStateException(cause, "Resource [%s] is not resolvable as a file", getCacheXml()); + } + } + + /** + * Returns a boolean value used to determine whether the cache will be closed on shutdown of the Spring application. + * + * @return a boolean value used to determine whether the cache will be closed on shutdown of the Spring application. + */ + public boolean isClose() { + return this.close; + } + + /** + * Sets a boolean value used to determine whether the cache should be closed on shutdown of the Spring application. + * + * @param close boolean value used to determine whether the cache will be closed on shutdown + * of the Spring application. + */ + public void setClose(boolean close) { + this.close = close; + } + + /** + * Sets the {@link GemFireCache#getCopyOnRead()} property of the {@link GemFireCache cache}. + * + * @param copyOnRead a {@link Boolean value} indicating whether {@link Object objects} + * stored in the {@link GemFireCache cache} are copied on read (i.e. {@link Region#get(Object)}. + */ + public void setCopyOnRead(@Nullable Boolean copyOnRead) { + this.copyOnRead = copyOnRead; + } + + /** + * Returns the configuration of the {@link GemFireCache#getCopyOnRead()} property on the {@link GemFireCache cache}. + * + * @return a {@link Boolean value} indicating whether {@link Object objects} + * stored in the {@link GemFireCache cache} are copied on read (i.e. {@link Region#get(Object)}. + */ + public @Nullable Boolean getCopyOnRead() { + return this.copyOnRead; + } + + /** + * Determines whether {@link Object objects} stored in the {@link GemFireCache cache} are copied + * when read (i.e. {@link Region#get(Object)}. + * + * @return a boolean value indicating whether {@link Object objects} stored in the {@link GemFireCache cache} + * are copied on read (i.e. {@link Region#get(Object)}. + */ + public boolean isCopyOnRead() { + return Boolean.TRUE.equals(this.copyOnRead); + } + + /** + * Set the Cache's critical heap percentage attribute. + * + * @param criticalHeapPercentage floating point value indicating the critical heap percentage. + */ + public void setCriticalHeapPercentage(@Nullable Float criticalHeapPercentage) { + this.criticalHeapPercentage = criticalHeapPercentage; + } + + /** + * @return the criticalHeapPercentage + */ + public Float getCriticalHeapPercentage() { + return this.criticalHeapPercentage; + } + + /** + * Set the cache's critical off-heap percentage property. + * + * @param criticalOffHeapPercentage floating point value indicating the critical off-heap percentage. + */ + public void setCriticalOffHeapPercentage(@Nullable Float criticalOffHeapPercentage) { + this.criticalOffHeapPercentage = criticalOffHeapPercentage; + } + + /** + * @return the criticalOffHeapPercentage + */ + public Float getCriticalOffHeapPercentage() { + return this.criticalOffHeapPercentage; + } + + /** + * Set the Cache's eviction heap percentage attribute. + * + * @param evictionHeapPercentage float-point value indicating the Cache's heap use percentage to trigger eviction. + */ + public void setEvictionHeapPercentage(Float evictionHeapPercentage) { + this.evictionHeapPercentage = evictionHeapPercentage; + } + + /** + * @return the evictionHeapPercentage + */ + public Float getEvictionHeapPercentage() { + return this.evictionHeapPercentage; + } + + /** + * Set the cache's eviction off-heap percentage property. + * + * @param evictionOffHeapPercentage float-point value indicating the percentage of off-heap use triggering eviction. + */ + public void setEvictionOffHeapPercentage(Float evictionOffHeapPercentage) { + this.evictionOffHeapPercentage = evictionOffHeapPercentage; + } + + /** + * @return the evictionOffHeapPercentage + */ + public Float getEvictionOffHeapPercentage() { + return this.evictionOffHeapPercentage; + } + + /** + * Returns the cache object reference created by this cache {@link FactoryBean}. + * + * @return the cache object reference created by this cache {@link FactoryBean}. + * @see org.springframework.beans.factory.FactoryBean#getObject() + * @see org.apache.geode.cache.GemFireCache + * @see #doGetObject() + * @see #getCache() + */ + @Override + public GemFireCache getObject() throws Exception { + return Optional.ofNullable(getCache()).orElseGet(this::doGetObject); + } + + protected abstract GemFireCache doGetObject(); + + /** + * Returns the {@link Class type} of {@link GemFireCache} produced by this cache {@link FactoryBean}. + * + * @return the {@link Class type} type of {@link GemFireCache} produced by this cache {@link FactoryBean}. + * @see org.springframework.beans.factory.FactoryBean#getObjectType() + */ + @Override + public Class getObjectType() { + + GemFireCache cache = getCache(); + + return cache != null ? cache.getClass() : doGetObjectType(); + } + + protected Class doGetObjectType() { + return GemFireCache.class; + } + + /** + * Set the lifecycle phase for this cache bean in the Spring container. + * + * @param phase {@link Integer#TYPE} value used as the lifecycle phase for this cache bean in the Spring container. + * @see org.springframework.context.Phased#getPhase() + */ + protected void setPhase(int phase) { + this.phase = phase; + } + + /** + * Returns the configured lifecycle phase for this cache bean in the Spring container. + * + * @return an {@link Integer#TYPE} used as the lifecycle phase for this cache bean in the Spring container. + * @see org.springframework.context.Phased#getPhase() + */ + @Override + public int getPhase() { + return this.phase; + } + + /** + * Sets and then returns a reference to Apache Geode {@link Properties} used to configure the cache. + * + * @param properties reference to Apache Geode {@link Properties} used to configure the cache. + * @return a reference to Apache Geode {@link Properties} used to configure the cache. + * @see #setProperties(Properties) + * @see #getProperties() + * @see java.util.Properties + */ + public Properties setAndGetProperties(@Nullable Properties properties) { + setProperties(properties); + return getProperties(); + } + + /** + * Sets the Apache Geode {@link Properties} used to configure the cache. + * + * @param properties reference to Apache Geode {@link Properties} used to configure the cache. + * @see java.util.Properties + */ + public void setProperties(@Nullable Properties properties) { + this.properties = properties; + } + + /** + * Returns a reference to the Apache Geode {@link Properties} used to configure the cache. + * + * @return a reference to Apache Geode {@link Properties}. + * @see java.util.Properties + */ + public @Nullable Properties getProperties() { + return this.properties; + } + + /** + * Determines whether the {@link GemfireBeanFactoryLocator} has been enabled. + * + * @return a boolean value indicating whether the {@link GemfireBeanFactoryLocator} has been enabled. + * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator + */ + public boolean isUseBeanFactoryLocator() { + return this.useBeanFactoryLocator; + } + + /** + * Sets a boolean value used to determine whether to enable the {@link GemfireBeanFactoryLocator}. + * + * @param use boolean value used to determine whether to enable the {@link GemfireBeanFactoryLocator}. + * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator + */ + public void setUseBeanFactoryLocator(boolean use) { + this.useBeanFactoryLocator = use; + } + + /** + * Initializes this cache {@link FactoryBean} after all properties for this cache bean have been set + * by the Spring container. + * + * @throws Exception if initialization fails. + * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() + * @see #applyCacheConfigurers() + * @see #initBeanFactoryLocator() + */ + @Override + public void afterPropertiesSet() throws Exception { + applyCacheConfigurers(); + initBeanFactoryLocator(); + } + + /** + * Applies any user-defined cache configurers (e.g. {@link ClientCacheConfigurer} or {@link PeerCacheConfigurer}) + * to this cache {@link FactoryBean} before cache construction, configuration and initialization. + */ + protected abstract void applyCacheConfigurers(); + + /** + * Null-safe method used to close the {@link GemFireCache} by calling {@link GemFireCache#close()} + * iff the cache is not already closed. + * + * @param cache {@link GemFireCache} to close. + * @see org.apache.geode.cache.GemFireCache#isClosed() + * @see org.apache.geode.cache.GemFireCache#close() + */ + protected void close(@Nullable GemFireCache cache) { + + Optional.ofNullable(cache) + .filter(it -> !it.isClosed()) + .ifPresent(GemFireCache::close); + + setCache(null); + } + + /** + * Destroys the cache bean on Spring Container shutdown. + * + * @see org.springframework.beans.factory.DisposableBean#destroy() + * @see #destroyBeanFactoryLocator() + * @see #close(GemFireCache) + * @see #isClose() + */ + @Override + public void destroy() { + + if (isClose()) { + close(fetchCache()); + destroyBeanFactoryLocator(); + } + } + + /** + * Destroys the {@link GemfireBeanFactoryLocator}. + * + * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator#destroy() + */ + protected void destroyBeanFactoryLocator() { + + Optional.ofNullable(getBeanFactoryLocator()) + .ifPresent(GemfireBeanFactoryLocator::destroy); + + setBeanFactoryLocator(null); + } + + private boolean isHeapPercentageValid(@NonNull Float heapPercentage) { + return heapPercentage >= 0.0f && heapPercentage <= 100.0f; + } + + protected GemFireCache configureHeapPercentages(GemFireCache cache) { + + Optional.ofNullable(getCriticalHeapPercentage()).ifPresent(criticalHeapPercentage -> { + + Assert.isTrue(isHeapPercentageValid(criticalHeapPercentage), String.format( + "criticalHeapPercentage [%s] is not valid; must be >= 0.0 and <= 100.0", criticalHeapPercentage)); + + cache.getResourceManager().setCriticalHeapPercentage(criticalHeapPercentage); + }); + + Optional.ofNullable(getEvictionHeapPercentage()).ifPresent(evictionHeapPercentage -> { + + Assert.isTrue(isHeapPercentageValid(evictionHeapPercentage), String.format( + "evictionHeapPercentage [%s] is not valid; must be >= 0.0 and <= 100.0", evictionHeapPercentage)); + + cache.getResourceManager().setEvictionHeapPercentage(evictionHeapPercentage); + }); + + return cache; + } + + protected GemFireCache configureOffHeapPercentages(GemFireCache cache) { + + Optional.ofNullable(getCriticalOffHeapPercentage()).ifPresent(criticalOffHeapPercentage -> { + + Assert.isTrue(isHeapPercentageValid(criticalOffHeapPercentage), String.format( + "criticalOffHeapPercentage [%s] is not valid; must be >= 0.0 and <= 100.0", criticalOffHeapPercentage)); + + cache.getResourceManager().setCriticalOffHeapPercentage(criticalOffHeapPercentage); + }); + + Optional.ofNullable(getEvictionOffHeapPercentage()).ifPresent(evictionOffHeapPercentage -> { + + Assert.isTrue(isHeapPercentageValid(evictionOffHeapPercentage), String.format( + "evictionOffHeapPercentage [%s] is not valid; must be >= 0.0 and <= 100.0", evictionOffHeapPercentage)); + + cache.getResourceManager().setEvictionOffHeapPercentage(evictionOffHeapPercentage); + }); + + return cache; + } + + /** + * Fetches an existing cache instance from the Apache Geode cache factory. + * + * @param parameterized {@link Class} type extending {@link GemFireCache}. + * @return an existing cache instance if available. + * @throws org.apache.geode.cache.CacheClosedException if an existing cache instance does not exist. + * @see org.apache.geode.cache.client.ClientCacheFactory#getAnyInstance() + * @see org.apache.geode.cache.CacheFactory#getAnyInstance() + * @see org.apache.geode.cache.GemFireCache + * @see #doFetchCache() + * @see #getCache() + */ + protected T fetchCache() { + + T cache = getCache(); + + return cache != null ? cache : doFetchCache(); + } + + protected abstract T doFetchCache(); + + /** + * Initializes the {@link GemfireBeanFactoryLocator} if {@link #isUseBeanFactoryLocator()} returns {@literal true} + * and an existing {@link #getBeanFactoryLocator()} is not already present. + * + * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator#newBeanFactoryLocator(BeanFactory, String) + * @see #isUseBeanFactoryLocator() + * @see #getBeanFactoryLocator() + * @see #getBeanFactory() + * @see #getBeanName() + */ + protected void initBeanFactoryLocator() { + + if (isUseBeanFactoryLocator() && getBeanFactoryLocator() == null) { + setBeanFactoryLocator(GemfireBeanFactoryLocator.newBeanFactoryLocator(getBeanFactory(), getBeanName())); + } + } + + /** + * Initializes the given {@link CacheFactory} or {@link ClientCacheFactory} + * with the configured {@link CacheFactoryInitializer}. + * + * @param factory {@link CacheFactory} or {@link ClientCacheFactory} to initialize. + * @return the initialized {@link CacheFactory} or {@link ClientCacheFactory}. + * @see org.springframework.data.gemfire.CacheFactoryBean.CacheFactoryInitializer#initialize(Object) + * @see org.apache.geode.cache.client.ClientCacheFactory + * @see org.apache.geode.cache.CacheFactory + * @see #getCacheFactoryInitializer() + */ + @Nullable + @SuppressWarnings("unchecked") + protected Object initializeFactory(Object factory) { + + return Optional.ofNullable(getCacheFactoryInitializer()) + .map(cacheFactoryInitializer -> cacheFactoryInitializer.initialize(factory)) + .orElse(factory); + } + + /** + * Loads the configured {@literal cache.xml} to initialize the cache. + * + * @param parameterized {@link Class} type extending {@link GemFireCache}. + * @param cache cache instance to initialized with {@literal cache.xml}. + * @return the given cache instance. + * @throws RuntimeException if the configured {@literal cache.xml} file could not be loaded. + * @see org.apache.geode.cache.GemFireCache#loadCacheXml(InputStream) + */ + protected T loadCacheXml(T cache) { + + // Load the cache.xml file (Resource) and initialize the cache + Optional.ofNullable(getCacheXml()).ifPresent(cacheXml -> { + try { + logDebug("Initializing cache with [%s]", cacheXml); + cache.loadCacheXml(cacheXml.getInputStream()); + } + catch (IOException cause) { + throw newRuntimeException(cause, "Failed to load cache.xml [%s]", cacheXml); + } + }); + + return cache; + } + + /** + * Resolves the Apache Geode {@link Properties} used to configure the {@link Cache}. + * + * @return the resolved Apache Geode {@link Properties} used to configure the {@link Cache}. + * @see #setAndGetProperties(Properties) + * @see #getProperties() + */ + protected Properties resolveProperties() { + + return Optional.ofNullable(getProperties()) + .orElseGet(() -> setAndGetProperties(new Properties())); + } + + /** + * Translates the thrown Apache Geode {@link RuntimeException} to a corresponding {@link Exception} from Spring's + * generic {@link DataAccessException} hierarchy if possible. + * + * @param exception the Apache Geode {@link RuntimeException} to translate. + * @return the translated Spring {@link DataAccessException} or {@literal null} + * if the Apache Geode {@link RuntimeException} could not be translated. + * @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(RuntimeException) + * @see org.springframework.dao.DataAccessException + */ + @Override + public DataAccessException translateExceptionIfPossible(@Nullable RuntimeException exception) { + + if (exception instanceof IllegalArgumentException) { + + DataAccessException wrapped = GemfireCacheUtils.convertQueryExceptions(exception); + + // ignore conversion if generic exception is returned + if (!(wrapped instanceof GemfireSystemException)) { + return wrapped; + } + } + + if (exception instanceof GemFireException) { + return GemfireCacheUtils.convertGemfireAccessException((GemFireException) exception); + } + + if (exception.getCause() instanceof GemFireException) { + return GemfireCacheUtils.convertGemfireAccessException((GemFireException) exception.getCause()); + } + + if (exception.getCause() instanceof GemFireCheckedException) { + return GemfireCacheUtils.convertGemfireAccessException((GemFireCheckedException) exception.getCause()); + } + + return null; + } + + /** + * Callback interface for initializing either a {@link CacheFactory} or a {@link ClientCacheFactory} instance, + * which is used to create an instance of {@link GemFireCache}. + * + * @see org.apache.geode.cache.CacheFactory + * @see org.apache.geode.cache.client.ClientCacheFactory + */ + @FunctionalInterface + public interface CacheFactoryInitializer { + + /** + * Initialize the given cache factory. + * + * @param cacheFactory cache factory to initialize. + * @return the given cache factory. + * @see org.apache.geode.cache.CacheFactory + * @see org.apache.geode.cache.client.ClientCacheFactory + */ + T initialize(T cacheFactory); + + } +} diff --git a/spring-data-geode/src/main/java/org/springframework/data/gemfire/AbstractPdxConfigurableCacheFactoryBean.java b/spring-data-geode/src/main/java/org/springframework/data/gemfire/AbstractPdxConfigurableCacheFactoryBean.java new file mode 100644 index 00000000..ea20f43c --- /dev/null +++ b/spring-data-geode/src/main/java/org/springframework/data/gemfire/AbstractPdxConfigurableCacheFactoryBean.java @@ -0,0 +1,209 @@ +/* + * Copyright 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.data.gemfire; + +import java.util.Optional; + +import org.apache.geode.cache.Cache; +import org.apache.geode.cache.DiskStore; +import org.apache.geode.cache.GemFireCache; +import org.apache.geode.cache.Region; +import org.apache.geode.cache.client.ClientCache; +import org.apache.geode.pdx.PdxSerializer; + +import org.springframework.lang.Nullable; +import org.springframework.util.StringUtils; + +/** + * Abstract base class encapsulating PDX configuration metadata applied to both Apache Geode {@link ClientCache} + * and {@literal peer} {@link Cache} instances. + * + * @author John Blum + * @see org.apache.geode.cache.Cache + * @see org.apache.geode.cache.GemFireCache + * @see org.apache.geode.cache.Region + * @see org.apache.geode.cache.client.ClientCache + * @see org.apache.geode.pdx.PdxSerializer + * @see org.springframework.data.gemfire.AbstractBasicCacheFactoryBean + * @since 2.5.0 + */ +public abstract class AbstractPdxConfigurableCacheFactoryBean extends AbstractBasicCacheFactoryBean { + + private Boolean pdxIgnoreUnreadFields; + private Boolean pdxPersistent; + private Boolean pdxReadSerialized; + + private PdxSerializer pdxSerializer; + + private String pdxDiskStoreName; + + /** + * Sets the {@link String name} of the Apache Geode {@link DiskStore} used to store PDX metadata. + * + * @param pdxDiskStoreName {@link String name} for the PDX {@link DiskStore}. + * @see org.apache.geode.cache.CacheFactory#setPdxDiskStore(String) + * @see org.apache.geode.cache.DiskStore#getName() + */ + public void setPdxDiskStoreName(@Nullable String pdxDiskStoreName) { + this.pdxDiskStoreName = pdxDiskStoreName; + } + + /** + * Gets the {@link String name} of the Apache Geode {@link DiskStore} used to store PDX metadata. + * + * @return the {@link String name} of the PDX {@link DiskStore}. + * @see org.apache.geode.cache.GemFireCache#getPdxDiskStore() + * @see org.apache.geode.cache.DiskStore#getName() + */ + public @Nullable String getPdxDiskStoreName() { + return this.pdxDiskStoreName; + } + + /** + * Configures whether PDX will ignore unread fields when deserializing PDX bytes back to an {@link Object}. + * + * Defaults to {@literal false}. + * + * @param pdxIgnoreUnreadFields {@link Boolean} value controlling ignoring unread fields. + * @see org.apache.geode.cache.CacheFactory#setPdxIgnoreUnreadFields(boolean) + */ + public void setPdxIgnoreUnreadFields(@Nullable Boolean pdxIgnoreUnreadFields) { + this.pdxIgnoreUnreadFields = pdxIgnoreUnreadFields; + } + + /** + * Gets the configuration determining whether PDX will ignore unread fields when deserializing PDX bytes + * back to an {@link Object}. + * + * Defaults to {@literal false}. + * + * @return a {@link Boolean} value controlling ignoring unread fields. + * @see org.apache.geode.cache.GemFireCache#getPdxIgnoreUnreadFields() + */ + public @Nullable Boolean getPdxIgnoreUnreadFields() { + return this.pdxIgnoreUnreadFields; + } + + /** + * Configures whether {@link Class type} metadata for {@link Object objects} serialized to PDX + * will be persisted to disk. + * + * @param pdxPersistent {@link Boolean} value controlling whether PDX {@link Class type} metadata + * will be persisted to disk. + * @see org.apache.geode.cache.CacheFactory#setPdxPersistent(boolean) + */ + public void setPdxPersistent(@Nullable Boolean pdxPersistent) { + this.pdxPersistent = pdxPersistent; + } + + /** + * Gets the configuration determining whether {@link Class type} metadata for {@link Object objects} serialized + * to PDX will be persisted to disk. + * + * @return a {@link Boolean} value controlling whether PDX {@link Class type} metadata will be persisted to disk. + * @see org.apache.geode.cache.GemFireCache#getPdxPersistent() + */ + public @Nullable Boolean getPdxPersistent() { + return this.pdxPersistent; + } + + /** + * Configures whether {@link Object objects} stored in the Apache Geode {@link GemFireCache cache} as PDX + * will be read back as PDX bytes or (deserialized) as an {@link Object} when {@link Region#get(Object)} + * is called. + * + * @param pdxReadSerialized {@link Boolean} value controlling the PDX read serialized function. + * @see org.apache.geode.cache.CacheFactory#setPdxReadSerialized(boolean) + */ + public void setPdxReadSerialized(@Nullable Boolean pdxReadSerialized) { + this.pdxReadSerialized = pdxReadSerialized; + } + + /** + * Gets the configuration determining whether {@link Object objects} stored in the Apache Geode + * {@link GemFireCache cache} as PDX will be read back as PDX bytes or (deserialized) as an {@link Object} + * when {@link Region#get(Object)} is called. + * + * @return a {@link Boolean} value controlling the PDX read serialized function. + * @see org.apache.geode.cache.GemFireCache#getPdxReadSerialized() + */ + public @Nullable Boolean getPdxReadSerialized() { + return this.pdxReadSerialized; + } + + /** + * Configures a reference to {@link PdxSerializer} used by this cache to de/serialize {@link Object objects} + * stored in the cache and distributed/transferred across the distributed system as PDX bytes. + * + * @param serializer {@link PdxSerializer} used by this cache to de/serialize {@link Object objects} as PDX. + * @see org.apache.geode.cache.CacheFactory#setPdxSerializer(PdxSerializer) + * @see org.apache.geode.pdx.PdxSerializer + */ + public void setPdxSerializer(@Nullable PdxSerializer serializer) { + this.pdxSerializer = serializer; + } + + /** + * Get a reference to the configured {@link PdxSerializer} used by this cache to de/serialize {@link Object objects} + * stored in the cache and distributed/transferred across the distributed system as PDX bytes. + * + * @return a reference to the configured {@link PdxSerializer}. + * @see org.apache.geode.cache.GemFireCache#getPdxSerializer() + * @see org.apache.geode.pdx.PdxSerializer + */ + public @Nullable PdxSerializer getPdxSerializer() { + return this.pdxSerializer; + } + + /** + * Configures the cache to use PDX serialization. + * + * @param pdxConfigurer {@link PdxConfigurer} used to configure the cache with PDX serialization. + * @return the {@link PdxConfigurer#getTarget()}. + */ + protected T configurePdx(PdxConfigurer pdxConfigurer) { + + Optional.ofNullable(getPdxDiskStoreName()) + .filter(StringUtils::hasText) + .ifPresent(pdxConfigurer::setDiskStoreName); + + Optional.ofNullable(getPdxIgnoreUnreadFields()).ifPresent(pdxConfigurer::setIgnoreUnreadFields); + + Optional.ofNullable(getPdxPersistent()).ifPresent(pdxConfigurer::setPersistent); + + Optional.ofNullable(getPdxReadSerialized()).ifPresent(pdxConfigurer::setReadSerialized); + + Optional.ofNullable(getPdxSerializer()).ifPresent(pdxConfigurer::setSerializer); + + return pdxConfigurer.getTarget(); + } + + public interface PdxConfigurer { + + T getTarget(); + + PdxConfigurer setDiskStoreName(String diskStoreName); + + PdxConfigurer setIgnoreUnreadFields(Boolean ignoreUnreadFields); + + PdxConfigurer setPersistent(Boolean persistent); + + PdxConfigurer setReadSerialized(Boolean readSerialized); + + PdxConfigurer setSerializer(PdxSerializer pdxSerializer); + + } +} diff --git a/spring-data-geode/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java b/spring-data-geode/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java index 39e94d0d..44b6d48c 100644 --- a/spring-data-geode/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java +++ b/spring-data-geode/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java @@ -15,72 +15,47 @@ */ package org.springframework.data.gemfire; -import static java.util.stream.StreamSupport.stream; import static org.springframework.data.gemfire.GemfireUtils.apacheGeodeProductName; import static org.springframework.data.gemfire.GemfireUtils.apacheGeodeVersion; -import static org.springframework.data.gemfire.support.GemfireBeanFactoryLocator.newBeanFactoryLocator; import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray; import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeCollection; -import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeIterable; import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeList; -import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException; import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newRuntimeException; -import java.io.File; -import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Properties; +import java.util.stream.StreamSupport; -import org.apache.geode.GemFireCheckedException; -import org.apache.geode.GemFireException; import org.apache.geode.cache.Cache; import org.apache.geode.cache.CacheClosedException; import org.apache.geode.cache.CacheFactory; import org.apache.geode.cache.GemFireCache; -import org.apache.geode.cache.RegionService; import org.apache.geode.cache.TransactionListener; import org.apache.geode.cache.TransactionWriter; -import org.apache.geode.cache.client.ClientCacheFactory; import org.apache.geode.cache.util.GatewayConflictResolver; import org.apache.geode.distributed.DistributedSystem; import org.apache.geode.internal.datasource.ConfigProperty; import org.apache.geode.internal.jndi.JNDIInvoker; -import org.apache.geode.pdx.PdxSerializable; import org.apache.geode.pdx.PdxSerializer; import org.apache.geode.security.SecurityManager; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.FactoryBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.context.Phased; -import org.springframework.core.io.Resource; -import org.springframework.dao.DataAccessException; -import org.springframework.dao.support.PersistenceExceptionTranslator; import org.springframework.data.gemfire.config.annotation.PeerCacheConfigurer; -import org.springframework.data.gemfire.support.AbstractFactoryBeanSupport; -import org.springframework.data.gemfire.support.GemfireBeanFactoryLocator; +import org.springframework.data.gemfire.util.ArrayUtils; +import org.springframework.data.gemfire.util.CollectionUtils; import org.springframework.data.gemfire.util.SpringUtils; -import org.springframework.lang.Nullable; +import org.springframework.lang.NonNull; import org.springframework.util.Assert; -import org.springframework.util.StringUtils; /** - * Spring {@link FactoryBean} used to construct, configure and initialize a {@literal peer} {@link Cache). + * Spring {@link FactoryBean} used to construct, configure and initialize a {@literal peer} {@link Cache) instance. * * Allows either the retrieval of an existing, open {@link Cache} or the creation of a new {@link Cache}. * - * This class implements the {@link PersistenceExceptionTranslator} interface and is auto-detected by Spring's - * {@link org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor} for AOP-based translation - * of native persistent data store exceptions to Spring's {@link DataAccessException} hierarchy. Therefore, the presence - * of this class automatically enables a - * {@link org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor} - * to translate Pivotal GemFire/Apache Geode exceptions appropriately. - * * @author Costin Leau * @author David Turanski * @author John Blum @@ -89,96 +64,46 @@ import org.springframework.util.StringUtils; * @see org.apache.geode.cache.Cache * @see org.apache.geode.cache.CacheFactory * @see org.apache.geode.cache.GemFireCache - * @see org.apache.geode.cache.RegionService - * @see org.apache.geode.cache.client.ClientCacheFactory + * @see org.apache.geode.pdx.PdxSerializer + * @see org.apache.geode.security.SecurityManager * @see org.apache.geode.distributed.DistributedMember * @see org.apache.geode.distributed.DistributedSystem - * @see org.apache.geode.cache.pdx.PdxSerializer * @see org.springframework.beans.factory.BeanFactory - * @see org.springframework.beans.factory.DisposableBean * @see org.springframework.beans.factory.FactoryBean - * @see org.springframework.beans.factory.InitializingBean - * @see org.springframework.context.Phased - * @see org.springframework.core.io.Resource - * @see org.springframework.dao.support.PersistenceExceptionTranslator * @see org.springframework.data.gemfire.config.annotation.PeerCacheConfigurer - * @see org.springframework.data.gemfire.support.AbstractFactoryBeanSupport - * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator */ @SuppressWarnings("unused") -public class CacheFactoryBean extends AbstractFactoryBeanSupport - implements DisposableBean, InitializingBean, PersistenceExceptionTranslator, Phased { +public class CacheFactoryBean extends AbstractPdxConfigurableCacheFactoryBean { - private boolean close = true; - private boolean useBeanFactoryLocator = false; - - private int phase = -1; - - private Boolean copyOnRead; private Boolean enableAutoReconnect; - private Boolean pdxIgnoreUnreadFields; - private Boolean pdxPersistent; - private Boolean pdxReadSerialized; private Boolean useClusterConfiguration; - private CacheFactoryInitializer cacheFactoryInitializer; - - private GemFireCache cache; - - private Float criticalHeapPercentage; - private Float criticalOffHeapPercentage; - private Float evictionHeapPercentage; - private Float evictionOffHeapPercentage; - private GatewayConflictResolver gatewayConflictResolver; - protected GemfireBeanFactoryLocator beanFactoryLocator; - private Integer lockLease; private Integer lockTimeout; private Integer messageSyncInterval; private Integer searchTimeout; - private List peerCacheConfigurers = new ArrayList<>(); + private final List peerCacheConfigurers = new ArrayList<>(); private List jndiDataSources; private List transactionListeners; - private PdxSerializer pdxSerializer; - - private PeerCacheConfigurer compositePeerCacheConfigurer = (beanName, bean) -> + private final PeerCacheConfigurer compositePeerCacheConfigurer = (beanName, bean) -> nullSafeList(peerCacheConfigurers).forEach(peerCacheConfigurer -> peerCacheConfigurer.configure(beanName, bean)); - private Properties properties; - - private Resource cacheXml; - private String cacheResolutionMessagePrefix; - private String pdxDiskStoreName; private org.apache.geode.security.SecurityManager securityManager; private TransactionWriter transactionWriter; - /** - * Initializes this {@link CacheFactoryBean} after properties have been set by the Spring container. - * - * @throws Exception if initialization fails. - * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() - * @see #applyCacheConfigurers() - * @see #initBeanFactoryLocator() - */ - @Override - public void afterPropertiesSet() throws Exception { - applyCacheConfigurers(); - initBeanFactoryLocator(); - } - /** * Applies the composite {@link PeerCacheConfigurer PeerCacheConfigurers} to this {@link CacheFactoryBean} - * before creating the {@link Cache peer Cache}. + * before the {@link Cache peer cache} is created. * * @see #getCompositePeerCacheConfigurer() * @see #applyPeerCacheConfigurers(PeerCacheConfigurer...) @@ -189,10 +114,10 @@ public class CacheFactoryBean extends AbstractFactoryBeanSupport Properties gemfireProperties = resolveProperties(); - gemfireProperties.setProperty("disable-auto-reconnect", + gemfireProperties.setProperty(GemFireProperties.DISABLE_AUTO_RECONNECT.getName(), String.valueOf(!Boolean.TRUE.equals(getEnableAutoReconnect()))); - gemfireProperties.setProperty("use-cluster-configuration", + gemfireProperties.setProperty(GemFireProperties.USE_CLUSTER_CONFIGURATION.getName(), String.valueOf(Boolean.TRUE.equals(getUseClusterConfiguration()))); }; @@ -203,47 +128,46 @@ public class CacheFactoryBean extends AbstractFactoryBeanSupport } /** - * Applies the given array of {@link PeerCacheConfigurer PeerCacheConfigurers} to this {@link CacheFactoryBean}. + * Applies the array of {@link PeerCacheConfigurer PeerCacheConfigurers} to this {@link CacheFactoryBean} + * before the {@link Cache peer cache} is created. * - * @param peerCacheConfigurers array of {@link PeerCacheConfigurer PeerCacheConfigurers} applied to - * this {@link CacheFactoryBean}. + * @param peerCacheConfigurers array of {@link PeerCacheConfigurer PeerCacheConfigurers} + * applied to this {@link CacheFactoryBean}. * @see org.springframework.data.gemfire.config.annotation.PeerCacheConfigurer * @see #applyPeerCacheConfigurers(Iterable) */ protected void applyPeerCacheConfigurers(PeerCacheConfigurer... peerCacheConfigurers) { - applyPeerCacheConfigurers(Arrays.asList(nullSafeArray(peerCacheConfigurers, PeerCacheConfigurer.class))); + applyPeerCacheConfigurers(Arrays.asList(ArrayUtils.nullSafeArray(peerCacheConfigurers, PeerCacheConfigurer.class))); } /** - * Applies the given {@link Iterable} of {@link PeerCacheConfigurer PeerCacheConfigurers} - * to this {@link CacheFactoryBean}. + * Applies the {@link Iterable} of {@link PeerCacheConfigurer PeerCacheConfigurers} to this {@link CacheFactoryBean} + * before the {@link Cache peer cache} is created. * * @param peerCacheConfigurers {@link Iterable} of {@link PeerCacheConfigurer PeerCacheConfigurers} * applied to this {@link CacheFactoryBean}. * @see org.springframework.data.gemfire.config.annotation.PeerCacheConfigurer * @see java.lang.Iterable - * @see #applyPeerCacheConfigurers(PeerCacheConfigurer...) */ protected void applyPeerCacheConfigurers(Iterable peerCacheConfigurers) { - stream(nullSafeIterable(peerCacheConfigurers).spliterator(), false) - .forEach(clientCacheConfigurer -> clientCacheConfigurer.configure(getBeanName(), this)); + StreamSupport.stream(CollectionUtils.nullSafeIterable(peerCacheConfigurers).spliterator(), false) + .forEach(peerCacheConfigurer -> peerCacheConfigurer.configure(getBeanName(), this)); } /** - * Initializes the {@link GemfireBeanFactoryLocator} if {@link #isUseBeanFactoryLocator()} returns {@literal true} - * and an existing {@link #getBeanFactoryLocator()} is not already present. - * - * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator#newBeanFactoryLocator(BeanFactory, String) - * @see #isUseBeanFactoryLocator() - * @see #getBeanFactoryLocator() - * @see #getBeanFactory() - * @see #getBeanName() + * @inheritDoc */ - void initBeanFactoryLocator() { + @Override + protected GemFireCache doGetObject() { + return init(); + } - if (isUseBeanFactoryLocator() && this.beanFactoryLocator == null) { - this.beanFactoryLocator = newBeanFactoryLocator(getBeanFactory(), getBeanName()); - } + /** + * @inheritDoc + */ + @Override + protected Class doGetObjectType() { + return Cache.class; } /** @@ -261,7 +185,7 @@ public class CacheFactoryBean extends AbstractFactoryBeanSupport ClassLoader currentThreadContextClassLoader = Thread.currentThread().getContextClassLoader(); try { - // Use Spring Bean ClassLoader to load Spring configured, Pivotal GemFire/Apache Geode classes + // Use Spring Bean ClassLoader to load Spring configured Apache Geode classes Thread.currentThread().setContextClassLoader(getBeanClassLoader()); setCache(postProcess(resolveCache())); @@ -284,7 +208,7 @@ public class CacheFactoryBean extends AbstractFactoryBeanSupport return getCache(); } catch (Exception cause) { - throw newRuntimeException(cause, "Error occurred when initializing peer cache"); + throw newRuntimeException(cause, "An error occurred while initializing the cache"); } finally { Thread.currentThread().setContextClassLoader(currentThreadContextClassLoader); @@ -305,140 +229,91 @@ public class CacheFactoryBean extends AbstractFactoryBeanSupport * @see #configureFactory(Object) * @see #createCache(Object) */ - @SuppressWarnings("unchecked") protected T resolveCache() { try { this.cacheResolutionMessagePrefix = "Found existing"; - return (T) fetchCache(); + return fetchCache(); } catch (CacheClosedException cause) { this.cacheResolutionMessagePrefix = "Created new"; - return (T) createCache(postProcess(configureFactory(initializeFactory(createFactory(resolveProperties()))))); + return createCache(postProcess(configureFactory(initializeFactory(createFactory(resolveProperties()))))); } } - /** - * Fetches an existing {@link Cache} instance from the {@link CacheFactory}. - * - * @param parameterized {@link Class} type extension of {@link GemFireCache}. - * @return an existing {@link Cache} instance if available. - * @throws org.apache.geode.cache.CacheClosedException if an existing {@link Cache} instance does not exist. - * @see org.apache.geode.cache.CacheFactory#getAnyInstance() - * @see org.apache.geode.cache.GemFireCache - * @see #getCache() - */ + @Override @SuppressWarnings("unchecked") - protected T fetchCache() { - return (T) Optional.ofNullable(getCache()).orElseGet(CacheFactory::getAnyInstance); + protected T doFetchCache() { + return (T) CacheFactory.getAnyInstance(); } /** - * Resolves the Pivotal GemFire/Apache Geode {@link Properties} used to configure the {@link Cache}. + * Constructs a new instance of {@link CacheFactory} initialized with the given Apache Geode {@link Properties} + * used to construct, configure and initialize a new peer {@link Cache} instance. * - * @return the resolved Pivotal GemFire/Apache Geode {@link Properties} used to configure the {@link Cache}. - * @see #setAndGetProperties(Properties) - * @see #getProperties() - */ - protected Properties resolveProperties() { - return Optional.ofNullable(getProperties()).orElseGet(() -> setAndGetProperties(new Properties())); - } - - /** - * Constructs a new instance of {@link CacheFactory} initialized with the given Pivotal GemFire/Apache Geode - * {@link Properties} used to construct, configure and initialize an instance of a {@link Cache}. - * - * @param gemfireProperties {@link Properties} used by the {@link CacheFactory} to configure the {@link Cache}. - * @return a new instance of {@link CacheFactory} initialized with the given Pivotal GemFire/Apache Geode - * {@link Properties}. + * @param gemfireProperties {@link Properties} used by the {@link CacheFactory} to configure the peer {@link Cache}. + * @return a new instance of {@link CacheFactory} initialized with the given Apache Geode {@link Properties}. * @see org.apache.geode.cache.CacheFactory * @see java.util.Properties */ - protected Object createFactory(Properties gemfireProperties) { + protected @NonNull Object createFactory(@NonNull Properties gemfireProperties) { return new CacheFactory(gemfireProperties); } - /** - * Initializes the given {@link CacheFactory} with the configured {@link CacheFactoryInitializer}. - * - * @param factory {@link CacheFactory} to initialize; may be {@literal null}. - * @return the initialized {@link CacheFactory}. - * @see org.springframework.data.gemfire.CacheFactoryBean.CacheFactoryInitializer#initialize(Object) - * @see org.apache.geode.cache.CacheFactory - * @see #getCacheFactoryInitializer() - */ - @Nullable - @SuppressWarnings("unchecked") - protected Object initializeFactory(Object factory) { - - return Optional.ofNullable(getCacheFactoryInitializer()) - .map(cacheFactoryInitializer -> cacheFactoryInitializer.initialize(factory)) - .orElse(factory); - } - /** * Configures the {@link CacheFactory} used to create the {@link Cache}. * - * Sets PDX options specified by the user. - * * @param factory {@link CacheFactory} used to create the {@link Cache}. * @return the configured {@link CacheFactory}. + * @see #configurePdx(org.springframework.data.gemfire.AbstractPdxConfigurableCacheFactoryBean.PdxConfigurer) + * @see #configureSecurity(CacheFactory) * @see org.apache.geode.cache.CacheFactory - * @see #configurePdx(CacheFactory) */ - protected Object configureFactory(Object factory) { + protected @NonNull Object configureFactory(@NonNull Object factory) { return configureSecurity(configurePdx((CacheFactory) factory)); } /** - * Configures PDX for this peer {@link Cache} instance. + * Configures the {@link Cache} to use PDX serialization. * - * @param cacheFactory {@link CacheFactory} used to configure the peer {@link Cache} with PDX. + * @param cacheFactory {@link CacheFactory} to configure with PDX. * @return the given {@link CacheFactory}. + * @see org.springframework.data.gemfire.CacheFactoryBean.CacheFactoryToPdxConfigurerAdapter * @see org.apache.geode.cache.CacheFactory + * @see #configurePdx(PdxConfigurer) */ - private CacheFactory configurePdx(CacheFactory cacheFactory) { - - Optional.ofNullable(getPdxSerializer()).ifPresent(cacheFactory::setPdxSerializer); - - Optional.ofNullable(getPdxDiskStoreName()).filter(StringUtils::hasText) - .ifPresent(cacheFactory::setPdxDiskStore); - - Optional.ofNullable(getPdxIgnoreUnreadFields()).ifPresent(cacheFactory::setPdxIgnoreUnreadFields); - - Optional.ofNullable(getPdxPersistent()).ifPresent(cacheFactory::setPdxPersistent); - - Optional.ofNullable(getPdxReadSerialized()).ifPresent(cacheFactory::setPdxReadSerialized); - - return cacheFactory; + protected @NonNull CacheFactory configurePdx(@NonNull CacheFactory cacheFactory) { + return configurePdx(CacheFactoryToPdxConfigurerAdapter.from(cacheFactory)); } /** - * Configures security for this peer {@link Cache} instance. + * Configures the {@link Cache} with security. * - * @param cacheFactory {@link CacheFactory} used to configure the peer {@link Cache} with security. + * @param cacheFactory {@link CacheFactory} used to configure the peer {@link Cache} instance with security. * @return the given {@link CacheFactory}. * @see org.apache.geode.cache.CacheFactory */ - private CacheFactory configureSecurity(CacheFactory cacheFactory) { + private @NonNull CacheFactory configureSecurity(@NonNull CacheFactory cacheFactory) { - Optional.ofNullable(getSecurityManager()).ifPresent(cacheFactory::setSecurityManager); + org.apache.geode.security.SecurityManager securityManager = getSecurityManager(); - return cacheFactory; + return securityManager != null + ? cacheFactory.setSecurityManager(securityManager) + : cacheFactory; } /** - * Post processes the {@link CacheFactory} used to create the {@link Cache}. + * Post process the {@link CacheFactory} used to create the {@link Cache}. * * @param factory {@link CacheFactory} used to create the {@link Cache}. * @return the post processed {@link CacheFactory}. * @see org.apache.geode.cache.CacheFactory */ - protected Object postProcess(Object factory) { + protected @NonNull Object postProcess(@NonNull Object factory) { return factory; } @@ -452,27 +327,27 @@ public class CacheFactoryBean extends AbstractFactoryBeanSupport * @see org.apache.geode.cache.GemFireCache */ @SuppressWarnings("unchecked") - protected T createCache(Object factory) { + protected @NonNull T createCache(@NonNull Object factory) { return (T) ((CacheFactory) factory).create(); } /** - * Post processes the {@link GemFireCache} by loading any {@literal cache.xml}, applying custom settings + * Post process the {@link GemFireCache} by loading any {@literal cache.xml} file, applying custom settings * specified in SDG XML configuration meta-data, and registering appropriate Transaction Listeners, Writer - * and JNDI settings. + * and JNDI settings along with JVM Heap configuration. * - * @param Parameterized {@link Class} type extension of {@link GemFireCache}. - * @param cache {@link GemFireCache} instance to post process. + * @param parameterized {@link Class} type extending {@link GemFireCache}. + * @param cache {@link GemFireCache} to post process. * @return the given {@link GemFireCache}. + * @see #loadCacheXml(GemFireCache) * @see org.apache.geode.cache.Cache#loadCacheXml(java.io.InputStream) - * @see #getCacheXml() * @see #configureHeapPercentages(org.apache.geode.cache.GemFireCache) - * @see #registerJndiDataSources() + * @see #configureOffHeapPercentages(GemFireCache) + * @see #registerJndiDataSources(GemFireCache) * @see #registerTransactionListeners(org.apache.geode.cache.GemFireCache) * @see #registerTransactionWriter(org.apache.geode.cache.GemFireCache) */ - @SuppressWarnings("all") - protected T postProcess(T cache) { + protected @NonNull T postProcess(@NonNull T cache) { loadCacheXml(cache); @@ -495,68 +370,6 @@ public class CacheFactoryBean extends AbstractFactoryBeanSupport return cache; } - private T loadCacheXml(T cache) { - - // Load cache.xml Resource and initialize the cache - Optional.ofNullable(getCacheXml()).ifPresent(cacheXml -> { - try { - logDebug("Initializing cache with [%s]", cacheXml); - cache.loadCacheXml(cacheXml.getInputStream()); - } - catch (IOException cause) { - throw newRuntimeException(cause, "Failed to load cache.xml [%s]", cacheXml); - } - }); - - return cache; - } - - private boolean isHeapPercentageValid(Float heapPercentage) { - return heapPercentage >= 0.0f && heapPercentage <= 100.0f; - } - - private GemFireCache configureHeapPercentages(GemFireCache cache) { - - Optional.ofNullable(getCriticalHeapPercentage()).ifPresent(criticalHeapPercentage -> { - - Assert.isTrue(isHeapPercentageValid(criticalHeapPercentage), String.format( - "criticalHeapPercentage [%s] is not valid; must be >= 0.0 and <= 100.0", criticalHeapPercentage)); - - cache.getResourceManager().setCriticalHeapPercentage(criticalHeapPercentage); - }); - - Optional.ofNullable(getEvictionHeapPercentage()).ifPresent(evictionHeapPercentage -> { - - Assert.isTrue(isHeapPercentageValid(evictionHeapPercentage), String.format( - "evictionHeapPercentage [%s] is not valid; must be >= 0.0 and <= 100.0", evictionHeapPercentage)); - - cache.getResourceManager().setEvictionHeapPercentage(evictionHeapPercentage); - }); - - return cache; - } - - private GemFireCache configureOffHeapPercentages(GemFireCache cache) { - - Optional.ofNullable(getCriticalOffHeapPercentage()).ifPresent(criticalOffHeapPercentage -> { - - Assert.isTrue(isHeapPercentageValid(criticalOffHeapPercentage), String.format( - "criticalOffHeapPercentage [%s] is not valid; must be >= 0.0 and <= 100.0", criticalOffHeapPercentage)); - - cache.getResourceManager().setCriticalOffHeapPercentage(criticalOffHeapPercentage); - }); - - Optional.ofNullable(getEvictionOffHeapPercentage()).ifPresent(evictionOffHeapPercentage -> { - - Assert.isTrue(isHeapPercentageValid(evictionOffHeapPercentage), String.format( - "evictionOffHeapPercentage [%s] is not valid; must be >= 0.0 and <= 100.0", evictionOffHeapPercentage)); - - cache.getResourceManager().setEvictionOffHeapPercentage(evictionOffHeapPercentage); - }); - - return cache; - } - private GemFireCache registerJndiDataSources(GemFireCache cache) { nullSafeCollection(getJndiDataSources()).forEach(jndiDataSource -> { @@ -593,277 +406,6 @@ public class CacheFactoryBean extends AbstractFactoryBeanSupport return cache; } - /** - * Null-safe internal method used to close the {@link GemFireCache} and calling {@link GemFireCache#close()} - * iff the cache {@link GemFireCache#isClosed() is not already closed}. - * - * @param cache {@link GemFireCache} to close. - * @see org.apache.geode.cache.GemFireCache#isClosed() - * @see org.apache.geode.cache.GemFireCache#close() - */ - protected void close(GemFireCache cache) { - - Optional.ofNullable(cache) - .filter(it -> !it.isClosed()) - .ifPresent(RegionService::close); - - setCache(null); - } - - /** - * Destroys the {@link Cache} bean on Spring container shutdown. - * - * @see org.springframework.beans.factory.DisposableBean#destroy() - * @see #destroyBeanFactoryLocator() - * @see #close(GemFireCache) - * @see #isClose() - */ - @Override - public void destroy() { - - if (isClose()) { - close(fetchCache()); - destroyBeanFactoryLocator(); - } - } - - /** - * Destroys the {@link GemfireBeanFactoryLocator}. - * - * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator#destroy() - */ - private void destroyBeanFactoryLocator() { - Optional.ofNullable(getBeanFactoryLocator()).ifPresent(GemfireBeanFactoryLocator::destroy); - this.beanFactoryLocator = null; - } - - /** - * Translates the given Pivotal GemFire/Apache Geode {@link RuntimeException} thrown to a corresponding exception - * from Spring's generic {@link DataAccessException} hierarchy, if possible. - * - * @param exception {@link RuntimeException} to translate. - * @return the translated Spring {@link DataAccessException} or {@literal null} if the Pivotal GemFire/Apache Geode - * {@link RuntimeException} could not be converted. - * @see org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible(RuntimeException) - * @see org.springframework.dao.DataAccessException - */ - @Override - public DataAccessException translateExceptionIfPossible(RuntimeException exception) { - - if (exception instanceof IllegalArgumentException) { - - DataAccessException wrapped = GemfireCacheUtils.convertQueryExceptions(exception); - - // ignore conversion if generic exception is returned - if (!(wrapped instanceof GemfireSystemException)) { - return wrapped; - } - } - - if (exception instanceof GemFireException) { - return GemfireCacheUtils.convertGemfireAccessException((GemFireException) exception); - } - - if (exception.getCause() instanceof GemFireException) { - return GemfireCacheUtils.convertGemfireAccessException((GemFireException) exception.getCause()); - } - - if (exception.getCause() instanceof GemFireCheckedException) { - return GemfireCacheUtils.convertGemfireAccessException((GemFireCheckedException) exception.getCause()); - } - - return null; - } - - /** - * Returns a reference to the configured {@link GemfireBeanFactoryLocator} used to resolve Spring bean references - * in native Pivotal GemFire/Apache Geode native config (e.g. {@literal cache.xml}). - * - * @return a reference to the configured {@link GemfireBeanFactoryLocator}. - * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator - */ - public GemfireBeanFactoryLocator getBeanFactoryLocator() { - return this.beanFactoryLocator; - } - - /** - * Sets a reference to the constructed, configured an initialized {@link Cache} - * created by this {@link CacheFactoryBean}. - * - * @param cache {@link Cache} created by this {@link CacheFactoryBean}. - * @see org.apache.geode.cache.Cache - */ - protected void setCache(GemFireCache cache) { - this.cache = cache; - } - - /** - * Returns a direct reference to the constructed, configured an initialized {@link Cache} - * created by this {@link CacheFactoryBean}. - * - * @return a direct reference to the {@link Cache} created by this {@link CacheFactoryBean}. - * @see org.apache.geode.cache.Cache - */ - @SuppressWarnings("unchecked") - protected T getCache() { - return (T) this.cache; - } - - /** - * Sets a reference to the Pivotal GemFire/Apache Geode native {@literal cache.xml} {@link Resource}. - * - * @param cacheXml reference to the Pivotal GemFire/Apache Geode native {@literal cache.xml} {@link Resource}. - * @see org.springframework.core.io.Resource - */ - public void setCacheXml(Resource cacheXml) { - this.cacheXml = cacheXml; - } - - /** - * Returns a reference to the Pivotal GemFire/Apache Geode native {@literal cache.xml} - * as a Spring {@link Resource}. - * - * @return a reference to the Pivotal GemFire/Apache Geode native {@literal cache.xml} - * as a Spring {@link Resource}. - * @see org.springframework.core.io.Resource - */ - public Resource getCacheXml() { - return this.cacheXml; - } - - /** - * Returns the {@literal cache.xml} {@link Resource} as a {@link File}. - * - * @return the {@literal cache.xml} {@link Resource} as a {@link File}. - * @throws IllegalStateException if the {@link Resource} is not a valid {@link File} in the file system - * or a general problem exists accessing or reading the {@link File}. - * @see org.springframework.core.io.Resource - * @see java.io.File - * @see #getCacheXml() - */ - private File getCacheXmlFile() { - - try { - return getCacheXml().getFile(); - } - catch (Throwable cause) { - throw newIllegalStateException(cause, "Resource [%s] is not resolvable as a file", getCacheXml()); - } - } - - /** - * Determines whether the {@link Resource cache.xml} {@link File} is present. - * - * @return boolean value indicating whether a {@link Resource cache.xml} {@link File} is present. - * @see #getCacheXmlFile() - */ - private boolean isCacheXmlAvailable() { - return getCacheXml() != null; - } - - /** - * Returns an object reference to the {@link Cache} created by this {@link CacheFactoryBean}. - * - * @return an object reference to the {@link Cache} created by this {@link CacheFactoryBean}. - * @see org.springframework.beans.factory.FactoryBean#getObject() - * @see org.apache.geode.cache.Cache - * @see #getCache() - */ - @Override - public GemFireCache getObject() throws Exception { - return Optional.ofNullable(getCache()).orElseGet(this::init); - } - - /** - * Returns the {@link Class} type of the {@link GemFireCache} produced by this {@link CacheFactoryBean}. - * - * @return the {@link Class} type of the {@link GemFireCache} produced by this {@link CacheFactoryBean}. - * @see org.springframework.beans.factory.FactoryBean#getObjectType() - */ - @Override - public Class getObjectType() { - - Cache cache = getCache(); - - return cache != null ? cache.getClass() : Cache.class; - } - - /** - * Set the {@link CacheFactoryInitializer} that will be called to initialize the cache factory used to create - * the cache constructed by this {@link CacheFactoryBean}. - * - * @param cacheFactoryInitializer {@link CacheFactoryInitializer} configured to initialize the cache factory. - * @see org.springframework.data.gemfire.CacheFactoryBean.CacheFactoryInitializer - */ - @SuppressWarnings("rawtypes") - public void setCacheFactoryInitializer(CacheFactoryInitializer cacheFactoryInitializer) { - this.cacheFactoryInitializer = cacheFactoryInitializer; - } - - /** - * Return the {@link CacheFactoryInitializer} that will be called to initialize the cache factory used to create - * the cache constructed by this {@link CacheFactoryBean}. - * - * @return the {@link CacheFactoryInitializer} configured to initialize the cache factory. - * @see org.springframework.data.gemfire.CacheFactoryBean.CacheFactoryInitializer - */ - @SuppressWarnings("rawtypes") - public CacheFactoryInitializer getCacheFactoryInitializer() { - return this.cacheFactoryInitializer; - } - - /** - * Sets and then returns a reference to Pivotal GemFire/Apache Geode {@link Properties} used to configure the cache. - * - * @param properties reference to Pivotal GemFire/Apache Geode {@link Properties} used to configure the cache. - * @return a reference to Pivotal GemFire/Apache Geode {@link Properties} used to configure the cache. - * @see java.util.Properties - * @see #setProperties(Properties) - * @see #getProperties() - */ - protected Properties setAndGetProperties(Properties properties) { - setProperties(properties); - return getProperties(); - } - - /** - * Returns a reference to Pivotal GemFire/Apache Geode {@link Properties} used to configure the cache. - * - * @param properties reference to Pivotal GemFire/Apache Geode {@link Properties} used to configure the cache. - * @see java.util.Properties - */ - public void setProperties(Properties properties) { - this.properties = properties; - } - - /** - * Returns a reference to Pivotal GemFire/Apache Geode {@link Properties} used to configure the cache. - * - * @return a reference to Pivotal GemFire/Apache Geode {@link Properties}. - * @see java.util.Properties - */ - public Properties getProperties() { - return this.properties; - } - - /** - * Sets a value to indicate whether the cache will be closed on shutdown of the Spring container. - * - * @param close boolean value indicating whether the cache will be closed on shutdown of the Spring container. - */ - public void setClose(boolean close) { - this.close = close; - } - - /** - * Returns a boolean value indicating whether the cache will be closed on shutdown of the Spring container. - * - * @return a boolean value indicating whether the cache will be closed on shutdown of the Spring container. - */ - public boolean isClose() { - return this.close; - } - /** * Returns a reference to the Composite {@link PeerCacheConfigurer} used to apply additional configuration * to this {@link CacheFactoryBean} on Spring container initialization. @@ -875,54 +417,6 @@ public class CacheFactoryBean extends AbstractFactoryBeanSupport return this.compositePeerCacheConfigurer; } - /** - * Set the copyOnRead attribute of the Cache. - * - * @param copyOnRead a boolean value indicating whether the object stored in the Cache is copied on gets. - */ - public void setCopyOnRead(Boolean copyOnRead) { - this.copyOnRead = copyOnRead; - } - - /** - * @return the copyOnRead - */ - public Boolean getCopyOnRead() { - return this.copyOnRead; - } - - /** - * Set the Cache's critical heap percentage attribute. - * - * @param criticalHeapPercentage floating point value indicating the critical heap percentage. - */ - public void setCriticalHeapPercentage(Float criticalHeapPercentage) { - this.criticalHeapPercentage = criticalHeapPercentage; - } - - /** - * @return the criticalHeapPercentage - */ - public Float getCriticalHeapPercentage() { - return this.criticalHeapPercentage; - } - - /** - * Set the cache's critical off-heap percentage property. - * - * @param criticalOffHeapPercentage floating point value indicating the critical off-heap percentage. - */ - public void setCriticalOffHeapPercentage(Float criticalOffHeapPercentage) { - this.criticalOffHeapPercentage = criticalOffHeapPercentage; - } - - /** - * @return the criticalOffHeapPercentage - */ - public Float getCriticalOffHeapPercentage() { - return this.criticalOffHeapPercentage; - } - /** * Controls whether auto-reconnect functionality introduced in GemFire 8 is enabled or not. * @@ -943,38 +437,6 @@ public class CacheFactoryBean extends AbstractFactoryBeanSupport return this.enableAutoReconnect; } - /** - * Set the Cache's eviction heap percentage attribute. - * - * @param evictionHeapPercentage float-point value indicating the Cache's heap use percentage to trigger eviction. - */ - public void setEvictionHeapPercentage(Float evictionHeapPercentage) { - this.evictionHeapPercentage = evictionHeapPercentage; - } - - /** - * @return the evictionHeapPercentage - */ - public Float getEvictionHeapPercentage() { - return this.evictionHeapPercentage; - } - - /** - * Set the cache's eviction off-heap percentage property. - * - * @param evictionOffHeapPercentage float-point value indicating the percentage of off-heap use triggering eviction. - */ - public void setEvictionOffHeapPercentage(Float evictionOffHeapPercentage) { - this.evictionOffHeapPercentage = evictionOffHeapPercentage; - } - - /** - * @return the evictionOffHeapPercentage - */ - public Float getEvictionOffHeapPercentage() { - return this.evictionOffHeapPercentage; - } - /** * Requires GemFire 7.0 or higher * @param gatewayConflictResolver defined as Object in the signature for backward @@ -1057,114 +519,6 @@ public class CacheFactoryBean extends AbstractFactoryBeanSupport return this.messageSyncInterval; } - /** - * Set the phase for the {@link Cache} bean in the lifecycle managed by the Spring container. - * - * @param phase {@link Integer#TYPE int} value indicating the phase of this {@link Cache} bean - * in the lifecycle managed by the Spring container. - * @see org.springframework.context.Phased#getPhase() - */ - protected void setPhase(int phase) { - this.phase = phase; - } - - /** - * Returns the configured phase of the {@link Cache} bean in the lifecycle managed by the Spring container. - * - * @return an {@link Integer#TYPE int} value indicating the phase of this {@link Cache} bean in the lifecycle - * managed by the Spring container. - * @see org.springframework.context.Phased#getPhase() - */ - @Override - public int getPhase() { - return this.phase; - } - - /** - * Set the disk store that is used for PDX meta data. Applicable on GemFire - * 6.6 or higher. - * - * @param pdxDiskStoreName the pdxDiskStoreName to set - */ - public void setPdxDiskStoreName(String pdxDiskStoreName) { - this.pdxDiskStoreName = pdxDiskStoreName; - } - - /** - * @return the pdxDiskStoreName - */ - public String getPdxDiskStoreName() { - return this.pdxDiskStoreName; - } - - /** - * Controls whether pdx ignores fields that were unread during - * deserialization. Applicable on GemFire 6.6 or higher. - * - * @param pdxIgnoreUnreadFields the pdxIgnoreUnreadFields to set - */ - public void setPdxIgnoreUnreadFields(Boolean pdxIgnoreUnreadFields) { - this.pdxIgnoreUnreadFields = pdxIgnoreUnreadFields; - } - - /** - * @return the pdxIgnoreUnreadFields - */ - public Boolean getPdxIgnoreUnreadFields() { - return this.pdxIgnoreUnreadFields; - } - - /** - * Controls whether type metadata for PDX objects is persisted to disk. Applicable on GemFire 6.6 or higher. - * - * @param pdxPersistent a boolean value indicating that PDX type meta-data should be persisted to disk. - */ - public void setPdxPersistent(Boolean pdxPersistent) { - this.pdxPersistent = pdxPersistent; - } - - /** - * @return the pdxPersistent - */ - public Boolean getPdxPersistent() { - return this.pdxPersistent; - } - - /** - * Sets the object preference to PdxInstance. Applicable on GemFire 6.6 or higher. - * - * @param pdxReadSerialized a boolean value indicating the PDX instance should be returned from Region.get(key) - * when available. - */ - public void setPdxReadSerialized(Boolean pdxReadSerialized) { - this.pdxReadSerialized = pdxReadSerialized; - } - - /** - * @return the pdxReadSerialized - */ - public Boolean getPdxReadSerialized() { - return this.pdxReadSerialized; - } - - /** - * Sets the {@link PdxSerializable} for this cache. Applicable on GemFire - * 6.6 or higher. The argument is of type object for compatibility with - * GemFire 6.5. - * - * @param serializer pdx serializer configured for this cache. - */ - public void setPdxSerializer(PdxSerializer serializer) { - this.pdxSerializer = serializer; - } - - /** - * @return the pdxSerializer - */ - public PdxSerializer getPdxSerializer() { - return this.pdxSerializer; - } - /** * Null-safe operation to set an array of {@link PeerCacheConfigurer PeerCacheConfigurers} used to apply * additional configuration to this {@link CacheFactoryBean} when using Annotation-based configuration. @@ -1265,26 +619,6 @@ public class CacheFactoryBean extends AbstractFactoryBeanSupport return this.transactionWriter; } - /** - * Sets whether to enable the {@link GemfireBeanFactoryLocator}. - * - * @param use boolean value indicating whether to enable the {@link GemfireBeanFactoryLocator}. - * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator - */ - public void setUseBeanFactoryLocator(boolean use) { - this.useBeanFactoryLocator = use; - } - - /** - * Determines whether the {@link GemfireBeanFactoryLocator} has been enabled. - * - * @return a boolean value indicating whether the {@link GemfireBeanFactoryLocator} has been enabled. - * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator - */ - public boolean isUseBeanFactoryLocator() { - return this.useBeanFactoryLocator; - } - /** * Sets the state of the {@literal use-shared-configuration} Pivotal GemFire/Apache Geode * distribution configuration setting. @@ -1307,26 +641,53 @@ public class CacheFactoryBean extends AbstractFactoryBeanSupport return this.useClusterConfiguration; } - /** - * Callback interface for initializing either a {@link CacheFactory} or a {@link ClientCacheFactory} instance, - * which is used to create an instance of {@link GemFireCache}. - * - * @see org.apache.geode.cache.CacheFactory - * @see org.apache.geode.cache.client.ClientCacheFactory - */ - @FunctionalInterface - public interface CacheFactoryInitializer { + public static class CacheFactoryToPdxConfigurerAdapter implements PdxConfigurer { - /** - * Initialize the given cache factory. - * - * @param cacheFactory cache factory to initialize. - * @return the given cache factory. - * @see org.apache.geode.cache.CacheFactory - * @see org.apache.geode.cache.client.ClientCacheFactory - */ - T initialize(T cacheFactory); + public static CacheFactoryToPdxConfigurerAdapter from(@NonNull CacheFactory cacheFactory) { + return new CacheFactoryToPdxConfigurerAdapter(cacheFactory); + } + private final CacheFactory cacheFactory; + + protected CacheFactoryToPdxConfigurerAdapter(@NonNull CacheFactory cacheFactory) { + Assert.notNull(cacheFactory, "CacheFactory must not be null"); + this.cacheFactory = cacheFactory; + } + + @Override + public @NonNull CacheFactory getTarget() { + return this.cacheFactory; + } + + @Override + public @NonNull PdxConfigurer setDiskStoreName(String diskStoreName) { + getTarget().setPdxDiskStore(diskStoreName); + return this; + } + + @Override + public @NonNull PdxConfigurer setIgnoreUnreadFields(Boolean ignoreUnreadFields) { + getTarget().setPdxIgnoreUnreadFields(ignoreUnreadFields); + return this; + } + + @Override + public @NonNull PdxConfigurer setPersistent(Boolean persistent) { + getTarget().setPdxPersistent(persistent); + return this; + } + + @Override + public @NonNull PdxConfigurer setReadSerialized(Boolean readSerialized) { + getTarget().setPdxReadSerialized(readSerialized); + return this; + } + + @Override + public @NonNull PdxConfigurer setSerializer(PdxSerializer pdxSerializer) { + getTarget().setPdxSerializer(pdxSerializer); + return this; + } } public static class JndiDataSource { diff --git a/spring-data-geode/src/main/java/org/springframework/data/gemfire/client/ClientCacheFactoryBean.java b/spring-data-geode/src/main/java/org/springframework/data/gemfire/client/ClientCacheFactoryBean.java index a593aa71..9ea057c7 100644 --- a/spring-data-geode/src/main/java/org/springframework/data/gemfire/client/ClientCacheFactoryBean.java +++ b/spring-data-geode/src/main/java/org/springframework/data/gemfire/client/ClientCacheFactoryBean.java @@ -16,9 +16,7 @@ package org.springframework.data.gemfire.client; import static java.util.stream.StreamSupport.stream; -import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray; import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeCollection; -import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeIterable; import java.net.InetSocketAddress; import java.util.Arrays; @@ -27,6 +25,8 @@ import java.util.List; import java.util.Optional; import java.util.Properties; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Supplier; +import java.util.stream.StreamSupport; import org.apache.geode.cache.CacheClosedException; import org.apache.geode.cache.GemFireCache; @@ -35,6 +35,7 @@ import org.apache.geode.cache.client.ClientCacheFactory; import org.apache.geode.cache.client.Pool; import org.apache.geode.cache.client.SocketFactory; import org.apache.geode.distributed.DistributedSystem; +import org.apache.geode.pdx.PdxSerializer; import org.springframework.beans.factory.FactoryBean; import org.springframework.context.ApplicationContext; @@ -50,9 +51,12 @@ import org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer; import org.springframework.data.gemfire.config.xml.GemfireConstants; import org.springframework.data.gemfire.support.ConnectionEndpoint; import org.springframework.data.gemfire.support.ConnectionEndpointList; +import org.springframework.data.gemfire.util.ArrayUtils; +import org.springframework.data.gemfire.util.CollectionUtils; import org.springframework.data.gemfire.util.SpringUtils; import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.StringUtils; /** @@ -67,12 +71,14 @@ import org.springframework.util.StringUtils; * @see org.apache.geode.cache.client.ClientCache * @see org.apache.geode.cache.client.ClientCacheFactory * @see org.apache.geode.cache.client.Pool + * @see org.apache.geode.cache.client.SocketFactory * @see org.apache.geode.distributed.DistributedSystem * @see org.apache.geode.pdx.PdxSerializer * @see org.springframework.beans.factory.BeanFactory * @see org.springframework.beans.factory.FactoryBean * @see org.springframework.context.ApplicationContext * @see org.springframework.context.ApplicationListener + * @see org.springframework.context.event.ApplicationContextEvent * @see org.springframework.context.event.ContextRefreshedEvent * @see org.springframework.data.gemfire.CacheFactoryBean * @see org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer @@ -90,8 +96,8 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat private Boolean subscriptionEnabled; private Boolean threadLocalConnections; - private ConnectionEndpointList locators = new ConnectionEndpointList(); - private ConnectionEndpointList servers = new ConnectionEndpointList(); + private final ConnectionEndpointList locators = new ConnectionEndpointList(); + private final ConnectionEndpointList servers = new ConnectionEndpointList(); private Integer durableClientTimeout; private Integer freeConnectionTimeout; @@ -129,7 +135,7 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat /** * Applies the composite {@link ClientCacheConfigurer ClientCacheConfigurers} - * to this {@link ClientCacheFactoryBean}. + * to this {@link ClientCacheFactoryBean} before the {@link ClientCache} is created. * * @see #getCompositeClientCacheConfigurer() * @see #applyClientCacheConfigurers(ClientCacheConfigurer...) @@ -140,21 +146,21 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat } /** - * Null-safe operation to apply the given array of {@link ClientCacheConfigurer ClientCacheConfigurers} - * to this {@link ClientCacheFactoryBean}. + * Applies the array of {@link ClientCacheConfigurer ClientCacheConfigurers} to this {@link ClientCacheFactoryBean} + * before the {@link ClientCache} is created. * - * @param clientCacheConfigurers array of {@link ClientCacheConfigurer ClientCacheConfigurers} applied to - * this {@link ClientCacheFactoryBean}. + * @param clientCacheConfigurers array of {@link ClientCacheConfigurer ClientCacheConfigurers} + * applied to this {@link ClientCacheFactoryBean}. * @see org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer * @see #applyClientCacheConfigurers(Iterable) */ protected void applyClientCacheConfigurers(ClientCacheConfigurer... clientCacheConfigurers) { - applyClientCacheConfigurers(Arrays.asList(nullSafeArray(clientCacheConfigurers, ClientCacheConfigurer.class))); + applyClientCacheConfigurers(Arrays.asList(ArrayUtils.nullSafeArray(clientCacheConfigurers, ClientCacheConfigurer.class))); } /** - * Null-safe operation to apply the given {@link Iterable} of {@link ClientCacheConfigurer ClientCacheConfigurers} - * to this {@link ClientCacheFactoryBean}. + * Apples the {@link Iterable} of {@link ClientCacheConfigurer ClientCacheConfigurers} + * to this {@link ClientCacheFactoryBean} before the {@link ClientCache} is created. * * @param clientCacheConfigurers {@link Iterable} of {@link ClientCacheConfigurer ClientCacheConfigurers} * applied to this {@link ClientCacheFactoryBean}. @@ -162,7 +168,7 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat * @see java.lang.Iterable */ protected void applyClientCacheConfigurers(Iterable clientCacheConfigurers) { - stream(nullSafeIterable(clientCacheConfigurers).spliterator(), false) + StreamSupport.stream(CollectionUtils.nullSafeIterable(clientCacheConfigurers).spliterator(), false) .forEach(clientCacheConfigurer -> clientCacheConfigurer.configure(getBeanName(), this)); } @@ -178,23 +184,39 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat */ @Override @SuppressWarnings("unchecked") - protected T fetchCache() { - return (T) Optional.ofNullable(getCache()).orElseGet(ClientCacheFactory::getAnyInstance); + protected T doFetchCache() { + return (T) ClientCacheFactory.getAnyInstance(); } /** - * Resolves the Pivotal GemFire/Apache Geode {@link Properties} used to configure the {@link ClientCache}. + * Returns the {@link Class type} of {@link GemFireCache} constructed by this {@link ClientCacheFactoryBean}. * - * @return the resolved Pivotal GemFire/Apache Geode {@link Properties} used to configure the {@link ClientCache}. - * @see org.apache.geode.distributed.DistributedSystem#getProperties() - * @see #getDistributedSystem() + * Returns {@link ClientCache} {@link Class}. + * + * @return the {@link Class type} of {@link GemFireCache} constructed by this {@link ClientCacheFactoryBean}. + * @see org.springframework.beans.factory.FactoryBean#getObjectType() */ @Override - protected Properties resolveProperties() { + public Class doGetObjectType() { + return ClientCache.class; + } + + /** + * Resolves the Apache Geode {@link Properties} used to configure the {@link ClientCache}. + * + * @return the resolved Apache Geode {@link Properties} used to configure the {@link ClientCache}. + * @see org.apache.geode.distributed.DistributedSystem#getProperties() + */ + @Override + protected @NonNull Properties resolveProperties() { + return resolveProperties(GemfireUtils::getDistributedSystem); + } + + @NonNull Properties resolveProperties(@NonNull Supplier distributeSystemSupplier) { Properties gemfireProperties = super.resolveProperties(); - DistributedSystem distributedSystem = getDistributedSystem(); + DistributedSystem distributedSystem = distributeSystemSupplier.get(); if (GemfireUtils.isConnected(distributedSystem)) { Properties distributedSystemProperties = (Properties) distributedSystem.getProperties().clone(); @@ -208,80 +230,60 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat } /** - * Returns the {@link DistributedSystem} formed from cache initialization. - * - * @param {@link Class} type of the {@link DistributedSystem}. - * @return an instance of the {@link DistributedSystem}. - * @see org.apache.geode.distributed.DistributedSystem - */ - T getDistributedSystem() { - return GemfireUtils.getDistributedSystem(); - } - - /** - * Constructs a new instance of {@link ClientCacheFactory} initialized with the given Pivotal GemFire/Apache Geode - * {@link Properties} used to construct, configure and initialize an instance of a {@link ClientCache}. + * Constructs a new instance of {@link ClientCacheFactory} initialized with the given Apache Geode {@link Properties} + * used to construct, configure and initialize a new {@link ClientCache} instance. * * @param gemfireProperties {@link Properties} used by the {@link ClientCacheFactory} * to configure the {@link ClientCache}. - * @return a new instance of {@link ClientCacheFactory} initialized with - * the given Pivotal GemFire/Apache Geode {@link Properties}. + * @return a new instance of {@link ClientCacheFactory} initialized with the given Apache Geode {@link Properties}. * @see org.apache.geode.cache.client.ClientCacheFactory * @see java.util.Properties */ @Override - protected Object createFactory(Properties gemfireProperties) { + protected @NonNull Object createFactory(@NonNull Properties gemfireProperties) { return new ClientCacheFactory(gemfireProperties); } /** * Configures the {@link ClientCacheFactory} used to create the {@link ClientCache}. * - * Sets PDX options specified by the user. - * - * Sets Pool options specified by the user. - * * @param factory {@link ClientCacheFactory} used to create the {@link ClientCache}. * @return the configured {@link ClientCacheFactory}. - * @see #configurePdx(ClientCacheFactory) + * @see org.apache.geode.cache.client.ClientCacheFactory + * @see #configurePool(ClientCacheFactory) + * @see #configurePdx(PdxConfigurer) */ @Override - protected Object configureFactory(Object factory) { + protected @NonNull Object configureFactory(@NonNull Object factory) { return configurePool(configurePdx((ClientCacheFactory) factory)); } /** - * Configure PDX for the {@link ClientCacheFactory}. + * Configures the {@link ClientCache} to use PDX serialization. * - * @param clientCacheFactory {@link ClientCacheFactory} used to configure PDX. - * @return the given {@link ClientCacheFactory} + * @param clientCacheFactory {@link ClientCacheFactory} to configure with PDX. + * @return the given {@link ClientCacheFactory}. + * @see org.springframework.data.gemfire.client.ClientCacheFactoryBean.ClientCacheFactoryToPdxConfigurerAdapter * @see org.apache.geode.cache.client.ClientCacheFactory + * @see #configurePdx(PdxConfigurer) */ - ClientCacheFactory configurePdx(ClientCacheFactory clientCacheFactory) { + protected @NonNull ClientCacheFactory configurePdx(@NonNull ClientCacheFactory clientCacheFactory) { - Optional.ofNullable(getPdxSerializer()).ifPresent(clientCacheFactory::setPdxSerializer); + PdxConfigurer pdxConfigurer = + ClientCacheFactoryToPdxConfigurerAdapter.from(clientCacheFactory); - Optional.ofNullable(getPdxDiskStoreName()).filter(StringUtils::hasText) - .ifPresent(clientCacheFactory::setPdxDiskStore); - - Optional.ofNullable(getPdxIgnoreUnreadFields()).ifPresent(clientCacheFactory::setPdxIgnoreUnreadFields); - - Optional.ofNullable(getPdxPersistent()).ifPresent(clientCacheFactory::setPdxPersistent); - - Optional.ofNullable(getPdxReadSerialized()).ifPresent(clientCacheFactory::setPdxReadSerialized); - - return clientCacheFactory; + return configurePdx(pdxConfigurer); } /** - * Configure the {@literal DEFAULT} {@link Pool} configuration settings with the {@link ClientCacheFactory} - * using a given {@link Pool} instance or a named {@link Pool}. + * Configure the {@literal DEFAULT} {@link Pool} of the {@link ClientCacheFactory} using a given {@link Pool} + * instance or a named {@link Pool} instance. * - * @param clientCacheFactory {@link ClientCacheFactory} use to configure the {@literal DEFAULT} {@link Pool}. + * @param clientCacheFactory {@link ClientCacheFactory} used to configure the {@literal DEFAULT} {@link Pool}. * @see org.apache.geode.cache.client.ClientCacheFactory * @see org.apache.geode.cache.client.Pool */ - ClientCacheFactory configurePool(ClientCacheFactory clientCacheFactory) { + protected @NonNull ClientCacheFactory configurePool(@NonNull ClientCacheFactory clientCacheFactory) { DefaultableDelegatingPoolAdapter pool = DefaultableDelegatingPoolAdapter.from(DelegatingPoolAdapter.from(resolvePool())).preferDefault(); @@ -346,7 +348,7 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat * @see #findPool(String) * @see #isPoolNameResolvable(String) */ - Pool resolvePool() { + protected Pool resolvePool() { Pool pool = getPool(); @@ -370,17 +372,6 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat return pool; } - String resolvePoolName() { - - return Optional.ofNullable(getPoolName()) - .filter(StringUtils::hasText) - .orElse(GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME); - } - - Pool findPool(String name) { - return getPoolResolver().resolve(name); - } - private boolean isPoolNameResolvable(String poolName) { return Optional.ofNullable(poolName) @@ -388,13 +379,29 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat .isPresent(); } + String resolvePoolName() { + + return Optional.ofNullable(getPoolName()) + .filter(StringUtils::hasText) + .orElseGet(this::getDefaultPoolName); + } + + String getDefaultPoolName() { + return GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME; + } + + Pool findPool(String name) { + return getPoolResolver().resolve(name); + } + /** - * Creates a new {@link ClientCache} instance using the provided factory. + * Creates a new {@link ClientCache} instance using the provided {@link ClientCacheFactory factory}. * - * @param parameterized {@link Class} type extension of {@link GemFireCache}. + * @param parameterized {@link Class} type extending {@link GemFireCache}. * @param factory instance of {@link ClientCacheFactory}. * @return a new instance of {@link ClientCache} created by the provided factory. * @see org.apache.geode.cache.client.ClientCacheFactory#create() + * @see org.apache.geode.cache.client.ClientCache * @see org.apache.geode.cache.GemFireCache */ @Override @@ -420,7 +427,7 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat this.fetchCache().readyForEvents(); } catch (IllegalStateException | CacheClosedException ignore) { - // Thrown when ClientCache.readyForEvents() is called on a non-durable client + // Exceptions are thrown when ClientCache.readyForEvents() is called on a non-durable client // or the ClientCache is closing. } } @@ -438,34 +445,6 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat ((ClientCache) cache).close(isKeepAlive()); } - /** - * @inheritDoc - */ - @Override - protected void setCache(GemFireCache cache) { - super.setCache(cache); - } - - /** - * @inheritDoc - */ - @Override - protected T getCache() { - return super.getCache(); - } - - /** - * Returns the {@link Class} type of the {@link GemFireCache} produced by this {@link ClientCacheFactoryBean}. - * - * @return the {@link Class} type of the {@link GemFireCache} produced by this {@link ClientCacheFactoryBean}. - * @see org.springframework.beans.factory.FactoryBean#getObjectType() - */ - @Override - @SuppressWarnings({ "rawtypes", "unchecked" }) - public Class getObjectType() { - return Optional.ofNullable(getCache()).map(Object::getClass).orElse((Class) ClientCache.class); - } - public void addLocators(ConnectionEndpoint... locators) { this.locators.add(locators); } @@ -492,7 +471,7 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat * @see #setClientCacheConfigurers(List) */ public void setClientCacheConfigurers(ClientCacheConfigurer... clientCacheConfigurers) { - setClientCacheConfigurers(Arrays.asList(nullSafeArray(clientCacheConfigurers, ClientCacheConfigurer.class))); + setClientCacheConfigurers(Arrays.asList(ArrayUtils.nullSafeArray(clientCacheConfigurers, ClientCacheConfigurer.class))); } /** @@ -504,7 +483,7 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat * @see org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer */ public void setClientCacheConfigurers(List peerCacheConfigurers) { - this.clientCacheConfigurers = Optional.ofNullable(peerCacheConfigurers).orElseGet(Collections::emptyList); + this.clientCacheConfigurers = peerCacheConfigurers != null ? peerCacheConfigurers : Collections.emptyList(); } /** @@ -766,9 +745,9 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat } /** - * Gets the user-specified value for the readyForEvents property. + * Gets the user-configured value for deciding that this client is ready to receive events from the server(s). * - * @return a boolean value indicating the state of the 'readyForEvents' property. + * @return a {@link Boolean} indicating whether this client is ready to receive events from the server(s). */ public Boolean getReadyForEvents(){ return this.readyForEvents; @@ -786,17 +765,8 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat Boolean readyForEvents = getReadyForEvents(); - if (readyForEvents != null) { - return Boolean.TRUE.equals(readyForEvents); - } - else { - try { - return GemfireUtils.isDurable(fetchCache()); - } - catch (Throwable ignore) { - return false; - } - } + return readyForEvents != null ? Boolean.TRUE.equals(readyForEvents) + : SpringUtils.safeGetValue(() -> GemfireUtils.isDurable(fetchCache()), false); } public void setRetryAttempts(Integer retryAttempts) { @@ -910,11 +880,60 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat @Override public final void setUseClusterConfiguration(Boolean useClusterConfiguration) { - throw new UnsupportedOperationException("Cluster-based Configuration is not applicable for clients"); + throw new UnsupportedOperationException("Cluster-based Configuration does not apply to clients"); } @Override public final Boolean getUseClusterConfiguration() { return Boolean.FALSE; } + + public static class ClientCacheFactoryToPdxConfigurerAdapter implements PdxConfigurer { + + public static ClientCacheFactoryToPdxConfigurerAdapter from(@NonNull ClientCacheFactory clientCacheFactory) { + return new ClientCacheFactoryToPdxConfigurerAdapter(clientCacheFactory); + } + + private final ClientCacheFactory cacheFactory; + + protected ClientCacheFactoryToPdxConfigurerAdapter(@NonNull ClientCacheFactory cacheFactory) { + Assert.notNull(cacheFactory, "ClientCacheFactory must not be null"); + this.cacheFactory = cacheFactory; + } + + @Override + public @NonNull ClientCacheFactory getTarget() { + return this.cacheFactory; + } + + @Override + public @NonNull PdxConfigurer setDiskStoreName(String diskStoreName) { + getTarget().setPdxDiskStore(diskStoreName); + return this; + } + + @Override + public @NonNull PdxConfigurer setIgnoreUnreadFields(Boolean ignoreUnreadFields) { + getTarget().setPdxIgnoreUnreadFields(ignoreUnreadFields); + return this; + } + + @Override + public @NonNull PdxConfigurer setPersistent(Boolean persistent) { + getTarget().setPdxPersistent(persistent); + return this; + } + + @Override + public @NonNull PdxConfigurer setReadSerialized(Boolean readSerialized) { + getTarget().setPdxReadSerialized(readSerialized); + return this; + } + + @Override + public @NonNull PdxConfigurer setSerializer(PdxSerializer pdxSerializer) { + getTarget().setPdxSerializer(pdxSerializer); + return this; + } + } } diff --git a/spring-data-geode/src/test/java/org/springframework/data/gemfire/CacheFactoryBeanTest.java b/spring-data-geode/src/test/java/org/springframework/data/gemfire/CacheFactoryBeanUnitTests.java similarity index 65% rename from spring-data-geode/src/test/java/org/springframework/data/gemfire/CacheFactoryBeanTest.java rename to spring-data-geode/src/test/java/org/springframework/data/gemfire/CacheFactoryBeanUnitTests.java index 7fa4d6be..1c290375 100644 --- a/spring-data-geode/src/test/java/org/springframework/data/gemfire/CacheFactoryBeanTest.java +++ b/spring-data-geode/src/test/java/org/springframework/data/gemfire/CacheFactoryBeanUnitTests.java @@ -13,42 +13,39 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.springframework.data.gemfire; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.nullValue; -import static org.hamcrest.Matchers.sameInstance; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.data.Offset.offset; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isA; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import static org.mockito.Mockito.withSettings; import java.io.InputStream; import java.util.Collections; import java.util.Properties; -import java.util.concurrent.atomic.AtomicBoolean; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InOrder; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; import org.apache.geode.cache.Cache; import org.apache.geode.cache.CacheClosedException; @@ -63,44 +60,35 @@ import org.apache.geode.distributed.DistributedMember; import org.apache.geode.distributed.DistributedSystem; import org.apache.geode.pdx.PdxSerializer; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InOrder; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - import org.springframework.beans.factory.BeanFactory; import org.springframework.core.io.Resource; +import org.springframework.data.gemfire.config.annotation.PeerCacheConfigurer; import org.springframework.data.gemfire.support.GemfireBeanFactoryLocator; /** - * Unit tests for {@link CacheFactoryBean}. + * Unit Tests for {@link CacheFactoryBean}. * * @author John Blum * @author Patrick Johnson - * @see java.io.InputStream * @see java.util.Properties * @see org.junit.Test - * @see org.junit.runner.RunWith * @see org.mockito.Mock * @see org.mockito.Mockito * @see org.mockito.junit.MockitoJUnitRunner * @see org.apache.geode.cache.Cache * @see org.apache.geode.cache.CacheFactory - * @see org.apache.geode.cache.CacheTransactionManager * @see org.apache.geode.cache.GemFireCache - * @see org.apache.geode.cache.control.ResourceManager - * @see org.apache.geode.cache.util.GatewayConflictResolver * @see org.apache.geode.distributed.DistributedMember * @see org.apache.geode.distributed.DistributedSystem * @see org.apache.geode.pdx.PdxSerializer * @see org.springframework.beans.factory.BeanFactory * @see org.springframework.core.io.Resource * @see org.springframework.data.gemfire.CacheFactoryBean + * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator * @since 1.7.0 */ @RunWith(MockitoJUnitRunner.class) -public class CacheFactoryBeanTest { +public class CacheFactoryBeanUnitTests { @Mock private Cache mockCache; @@ -114,7 +102,10 @@ public class CacheFactoryBeanTest { InOrder orderVerifier = inOrder(cacheFactoryBean); + orderVerifier.verify(cacheFactoryBean, times(1)).afterPropertiesSet(); orderVerifier.verify(cacheFactoryBean, times(1)).applyCacheConfigurers(); + orderVerifier.verify(cacheFactoryBean, times(1)).getCompositePeerCacheConfigurer(); + orderVerifier.verify(cacheFactoryBean, times(1)).applyPeerCacheConfigurers(isA(PeerCacheConfigurer.class)); orderVerifier.verify(cacheFactoryBean, times(1)).initBeanFactoryLocator(); } @@ -127,11 +118,12 @@ public class CacheFactoryBeanTest { Properties gemfireProperties = cacheFactoryBean.getProperties(); - assertThat(gemfireProperties.size(), is(equalTo(2))); - assertThat(gemfireProperties.containsKey("disable-auto-reconnect"), is(true)); - assertThat(gemfireProperties.containsKey("use-cluster-configuration"), is(true)); - assertThat(gemfireProperties.getProperty("disable-auto-reconnect"), is(equalTo("true"))); - assertThat(gemfireProperties.getProperty("use-cluster-configuration"), is(equalTo("false"))); + assertThat(gemfireProperties).isNotNull(); + assertThat(gemfireProperties).hasSize(2); + assertThat(gemfireProperties.containsKey("disable-auto-reconnect")).isTrue(); + assertThat(gemfireProperties.containsKey("use-cluster-configuration")).isTrue(); + assertThat(gemfireProperties.getProperty("disable-auto-reconnect")).isEqualTo("true"); + assertThat(gemfireProperties.getProperty("use-cluster-configuration")).isEqualTo("false"); } @Test @@ -145,11 +137,12 @@ public class CacheFactoryBeanTest { Properties gemfireProperties = cacheFactoryBean.getProperties(); - assertThat(gemfireProperties.size(), is(equalTo(2))); - assertThat(gemfireProperties.containsKey("disable-auto-reconnect"), is(true)); - assertThat(gemfireProperties.containsKey("use-cluster-configuration"), is(true)); - assertThat(gemfireProperties.getProperty("disable-auto-reconnect"), is(equalTo("true"))); - assertThat(gemfireProperties.getProperty("use-cluster-configuration"), is(equalTo("false"))); + assertThat(gemfireProperties).isNotNull(); + assertThat(gemfireProperties).hasSize(2); + assertThat(gemfireProperties.containsKey("disable-auto-reconnect")).isTrue(); + assertThat(gemfireProperties.containsKey("use-cluster-configuration")).isTrue(); + assertThat(gemfireProperties.getProperty("disable-auto-reconnect")).isEqualTo("true"); + assertThat(gemfireProperties.getProperty("use-cluster-configuration")).isEqualTo("false"); } @Test @@ -163,11 +156,12 @@ public class CacheFactoryBeanTest { Properties gemfireProperties = cacheFactoryBean.getProperties(); - assertThat(gemfireProperties.size(), is(equalTo(2))); - assertThat(gemfireProperties.containsKey("disable-auto-reconnect"), is(true)); - assertThat(gemfireProperties.containsKey("use-cluster-configuration"), is(true)); - assertThat(gemfireProperties.getProperty("disable-auto-reconnect"), is(equalTo("false"))); - assertThat(gemfireProperties.getProperty("use-cluster-configuration"), is(equalTo("true"))); + assertThat(gemfireProperties).isNotNull(); + assertThat(gemfireProperties).hasSize(2); + assertThat(gemfireProperties.containsKey("disable-auto-reconnect")).isTrue(); + assertThat(gemfireProperties.containsKey("use-cluster-configuration")).isTrue(); + assertThat(gemfireProperties.getProperty("disable-auto-reconnect")).isEqualTo("false"); + assertThat(gemfireProperties.getProperty("use-cluster-configuration")).isEqualTo("true"); } @Test @@ -181,11 +175,12 @@ public class CacheFactoryBeanTest { Properties gemfireProperties = cacheFactoryBean.getProperties(); - assertThat(gemfireProperties.size(), is(equalTo(2))); - assertThat(gemfireProperties.containsKey("disable-auto-reconnect"), is(true)); - assertThat(gemfireProperties.containsKey("use-cluster-configuration"), is(true)); - assertThat(gemfireProperties.getProperty("disable-auto-reconnect"), is(equalTo("true"))); - assertThat(gemfireProperties.getProperty("use-cluster-configuration"), is(equalTo("true"))); + assertThat(gemfireProperties).isNotNull(); + assertThat(gemfireProperties).hasSize(2); + assertThat(gemfireProperties.containsKey("disable-auto-reconnect")).isTrue(); + assertThat(gemfireProperties.containsKey("use-cluster-configuration")).isTrue(); + assertThat(gemfireProperties.getProperty("disable-auto-reconnect")).isEqualTo("true"); + assertThat(gemfireProperties.getProperty("use-cluster-configuration")).isEqualTo("true"); } @Test @@ -199,44 +194,52 @@ public class CacheFactoryBeanTest { Properties gemfireProperties = cacheFactoryBean.getProperties(); - assertThat(gemfireProperties.size(), is(equalTo(2))); - assertThat(gemfireProperties.containsKey("disable-auto-reconnect"), is(true)); - assertThat(gemfireProperties.containsKey("use-cluster-configuration"), is(true)); - assertThat(gemfireProperties.getProperty("disable-auto-reconnect"), is(equalTo("false"))); - assertThat(gemfireProperties.getProperty("use-cluster-configuration"), is(equalTo("false"))); + assertThat(gemfireProperties).isNotNull(); + assertThat(gemfireProperties).hasSize(2); + assertThat(gemfireProperties.containsKey("disable-auto-reconnect")).isTrue(); + assertThat(gemfireProperties.containsKey("use-cluster-configuration")).isTrue(); + assertThat(gemfireProperties.getProperty("disable-auto-reconnect")).isEqualTo("false"); + assertThat(gemfireProperties.getProperty("use-cluster-configuration")).isEqualTo("false"); } @Test public void getObjectCallsInit() throws Exception { - AtomicBoolean initCalled = new AtomicBoolean(false); - Cache mockCache = mock(Cache.class); - CacheFactoryBean cacheFactoryBean = new CacheFactoryBean() { - @Override Cache init() { - initCalled.set(true); - return mockCache; - } - }; + CacheFactoryBean cacheFactoryBean = spy(new CacheFactoryBean()); - assertThat(cacheFactoryBean.getObject(), is(sameInstance(mockCache))); - assertThat(initCalled.get(), is(true)); + doReturn(mockCache).when(cacheFactoryBean).init(); - verifyZeroInteractions(mockCache); + assertThat(cacheFactoryBean.getObject()).isSameAs(mockCache); + + verify(cacheFactoryBean, times(1)).getObject(); + verify(cacheFactoryBean, times(1)).getCache(); + verify(cacheFactoryBean, times(1)).doGetObject(); + verify(cacheFactoryBean, times(1)).init(); + + verifyNoMoreInteractions(cacheFactoryBean); + + verifyNoInteractions(mockCache); } @Test public void getObjectReturnsExistingCache() throws Exception { Cache mockCache = mock(Cache.class); - CacheFactoryBean cacheFactoryBean = new CacheFactoryBean(); + + CacheFactoryBean cacheFactoryBean = spy(new CacheFactoryBean()); cacheFactoryBean.setCache(mockCache); - assertThat(cacheFactoryBean.getObject(), is(sameInstance(mockCache))); + assertThat(cacheFactoryBean.getCache()).isSameAs(mockCache); + assertThat(cacheFactoryBean.getObject()).isSameAs(mockCache); - verifyZeroInteractions(mockCache); + verify(cacheFactoryBean, times(1)).getObject(); + verify(cacheFactoryBean, never()).doGetObject(); + verify(cacheFactoryBean, never()).init(); + + verifyNoInteractions(mockCache); } @Test @@ -285,17 +288,18 @@ public class CacheFactoryBeanTest { Properties gemfireProperties = new Properties(); - CacheFactoryBean cacheFactoryBean = new CacheFactoryBean() { + CacheFactoryBean cacheFactoryBean = spy(new CacheFactoryBean()); - @Override - protected Object createFactory(Properties actualGemfireProperties) { + doAnswer(invocation -> { - assertThat(actualGemfireProperties, is(equalTo(gemfireProperties))); - assertThat(getBeanClassLoader(), is(equalTo(ClassLoader.getSystemClassLoader()))); + Properties gemfirePropertiesArgument = invocation.getArgument(0); - return mockCacheFactory; - } - }; + assertThat(gemfirePropertiesArgument).isEqualTo(gemfireProperties); + assertThat(cacheFactoryBean.getBeanClassLoader()).isEqualTo(ClassLoader.getSystemClassLoader()); + + return mockCacheFactory; + + }).when(cacheFactoryBean).createFactory(isA(Properties.class)); cacheFactoryBean.setBeanClassLoader(ClassLoader.getSystemClassLoader()); cacheFactoryBean.setBeanFactory(mockBeanFactory); @@ -326,15 +330,15 @@ public class CacheFactoryBeanTest { cacheFactoryBean.afterPropertiesSet(); cacheFactoryBean.init(); - assertThat(Thread.currentThread().getContextClassLoader(), is(sameInstance(expectedThreadContextClassLoader))); + assertThat(Thread.currentThread().getContextClassLoader()).isSameAs(expectedThreadContextClassLoader); GemfireBeanFactoryLocator beanFactoryLocator = cacheFactoryBean.getBeanFactoryLocator(); - assertThat(beanFactoryLocator, is(notNullValue())); + assertThat(beanFactoryLocator).isNotNull(); BeanFactory beanFactoryReference = beanFactoryLocator.useBeanFactory("TestGemFireCache"); - assertThat(beanFactoryReference, is(sameInstance(mockBeanFactory))); + assertThat(beanFactoryReference).isSameAs(mockBeanFactory); verify(mockBeanFactory, times(1)).getAliases(anyString()); verify(mockCacheFactory, times(1)).setPdxDiskStore(eq("TestPdxDiskStore")); @@ -365,58 +369,59 @@ public class CacheFactoryBeanTest { Cache mockCache = mock(Cache.class); - CacheFactoryBean cacheFactoryBean = new CacheFactoryBean() { + CacheFactoryBean cacheFactoryBean = spy(new CacheFactoryBean()); - @Override @SuppressWarnings("unchecked ") - protected T fetchCache() { - return (T) mockCache; - } - }; + doReturn(mockCache).when(cacheFactoryBean).fetchCache(); - assertThat(cacheFactoryBean.resolveCache(), is(sameInstance(mockCache))); + assertThat(cacheFactoryBean.resolveCache()).isSameAs(mockCache); - verifyZeroInteractions(mockCache); + verifyNoInteractions(mockCache); } @Test public void resolveCacheCreatesCacheWhenFetchCacheThrowsCacheClosedException() { Cache mockCache = mock(Cache.class); + CacheFactory mockCacheFactory = mock(CacheFactory.class); - when(mockCacheFactory.create()).thenReturn(mockCache); + doReturn(mockCache).when(mockCacheFactory).create(); - CacheFactoryBean cacheFactoryBean = new CacheFactoryBean() { - @Override protected T fetchCache() { - throw new CacheClosedException("test"); - } + CacheFactoryBean cacheFactoryBean = spy(new CacheFactoryBean()); - @Override - protected Object createFactory(final Properties gemfireProperties) { - assertThat(gemfireProperties, is(sameInstance(getProperties()))); - return mockCacheFactory; - } - }; + doThrow(new CacheClosedException("TEST")).when(cacheFactoryBean).fetchCache(); - assertThat(cacheFactoryBean.resolveCache(), is(equalTo(mockCache))); + doAnswer(invocation -> { + + Properties gemfireProperties = invocation.getArgument(0); + + assertThat(gemfireProperties).isSameAs(cacheFactoryBean.getProperties()); + + return mockCacheFactory; + + }).when(cacheFactoryBean).createFactory(isA(Properties.class)); + + assertThat(cacheFactoryBean.resolveCache()).isEqualTo(mockCache); verify(mockCacheFactory, times(1)).create(); - verifyZeroInteractions(mockCache); + + verifyNoInteractions(mockCache); } @Test public void fetchExistingCache() { Cache mockCache = mock(Cache.class); + CacheFactoryBean cacheFactoryBean = new CacheFactoryBean(); cacheFactoryBean.setCache(mockCache); Cache actualCache = cacheFactoryBean.fetchCache(); - assertThat(actualCache, is(sameInstance(mockCache))); + assertThat(actualCache).isSameAs(mockCache); - verifyZeroInteractions(mockCache); + verifyNoInteractions(mockCache); } @Test @@ -428,7 +433,7 @@ public class CacheFactoryBeanTest { cacheFactoryBean.setProperties(gemfireProperties); - assertThat(cacheFactoryBean.resolveProperties(), is(sameInstance(gemfireProperties))); + assertThat(cacheFactoryBean.resolveProperties()).isSameAs(gemfireProperties); } @Test @@ -440,8 +445,8 @@ public class CacheFactoryBeanTest { Properties gemfireProperties = cacheFactoryBean.resolveProperties(); - assertThat(gemfireProperties, is(notNullValue())); - assertThat(gemfireProperties.isEmpty(), is(true)); + assertThat(gemfireProperties).isNotNull(); + assertThat(gemfireProperties.isEmpty()).isTrue(); } @Test @@ -451,20 +456,20 @@ public class CacheFactoryBeanTest { Object cacheFactoryReference = new CacheFactoryBean().createFactory(gemfireProperties); - assertThat(cacheFactoryReference, is(instanceOf(CacheFactory.class))); - assertThat(gemfireProperties.isEmpty(), is(true)); + assertThat(cacheFactoryReference).isInstanceOf(CacheFactory.class); + assertThat(gemfireProperties.isEmpty()).isTrue(); CacheFactory cacheFactory = (CacheFactory) cacheFactoryReference; cacheFactory.set("name", "TestCreateCacheFactory"); - assertThat(gemfireProperties.containsKey("name"), is(true)); - assertThat(gemfireProperties.getProperty("name"), is(equalTo("TestCreateCacheFactory"))); + assertThat(gemfireProperties.containsKey("name")).isTrue(); + assertThat(gemfireProperties.getProperty("name")).isEqualTo("TestCreateCacheFactory"); } @Test @SuppressWarnings("unchecked") - public void initializesFactoryWitCacheFactoryInitializer() { + public void initializesFactoryWithCacheFactoryInitializer() { CacheFactory mockCacheFactory = mock(CacheFactory.class); @@ -475,25 +480,24 @@ public class CacheFactoryBeanTest { cacheFactoryBean.setCacheFactoryInitializer(mockCacheFactoryInitializer); - assertThat(cacheFactoryBean.getCacheFactoryInitializer(), is(equalTo(mockCacheFactoryInitializer))); - assertThat(cacheFactoryBean.initializeFactory(mockCacheFactory), is(sameInstance(mockCacheFactory))); + assertThat(cacheFactoryBean.getCacheFactoryInitializer()).isEqualTo(mockCacheFactoryInitializer); + assertThat(cacheFactoryBean.initializeFactory(mockCacheFactory)).isSameAs(mockCacheFactory); verify(mockCacheFactoryInitializer, times(1)).initialize(eq(mockCacheFactory)); - verifyZeroInteractions(mockCacheFactory); + verifyNoInteractions(mockCacheFactory); } @Test - public void initializeFactoryWhenNoCacheFactoryInitializerIsPresentIsNullSafe() { + public void initializesFactoryWhenNoCacheFactoryInitializerIsPresentIsNullSafe() { CacheFactory mockCacheFactory = mock(CacheFactory.class); CacheFactoryBean cacheFactoryBean = new CacheFactoryBean(); - assertThat(cacheFactoryBean.getCacheFactoryInitializer(), - is(nullValue(CacheFactoryBean.CacheFactoryInitializer.class))); - assertThat(cacheFactoryBean.initializeFactory(mockCacheFactory), is(sameInstance(mockCacheFactory))); + assertThat(cacheFactoryBean.getCacheFactoryInitializer()).isNull(); + assertThat(cacheFactoryBean.initializeFactory(mockCacheFactory)).isSameAs(mockCacheFactory); - verifyZeroInteractions(mockCacheFactory); + verifyNoInteractions(mockCacheFactory); } @Test @@ -501,38 +505,46 @@ public class CacheFactoryBeanTest { CacheFactory mockCacheFactory = mock(CacheFactory.class); - assertThat(new CacheFactoryBean().configureFactory(mockCacheFactory), is(sameInstance(mockCacheFactory))); + CacheFactoryBean cacheFactoryBean = new CacheFactoryBean(); + + assertThat(cacheFactoryBean.configureFactory(mockCacheFactory)).isSameAs(mockCacheFactory); verify(mockCacheFactory, never()).setPdxDiskStore(any(String.class)); verify(mockCacheFactory, never()).setPdxIgnoreUnreadFields(any(Boolean.class)); verify(mockCacheFactory, never()).setPdxPersistent(any(Boolean.class)); verify(mockCacheFactory, never()).setPdxReadSerialized(any(Boolean.class)); verify(mockCacheFactory, never()).setPdxSerializer(any(PdxSerializer.class)); + + verifyNoInteractions(mockCacheFactory); } @Test public void configureFactoryWithSpecificPdxOptions() { + CacheFactory mockCacheFactory = mock(CacheFactory.class); + CacheFactoryBean cacheFactoryBean = new CacheFactoryBean(); cacheFactoryBean.setPdxSerializer(mock(PdxSerializer.class)); cacheFactoryBean.setPdxReadSerialized(true); cacheFactoryBean.setPdxIgnoreUnreadFields(false); - CacheFactory mockCacheFactory = mock(CacheFactory.class); - - assertThat(cacheFactoryBean.configureFactory(mockCacheFactory), is(sameInstance(mockCacheFactory))); + assertThat(cacheFactoryBean.configureFactory(mockCacheFactory)).isSameAs(mockCacheFactory); verify(mockCacheFactory, never()).setPdxDiskStore(any(String.class)); verify(mockCacheFactory, times(1)).setPdxIgnoreUnreadFields(eq(false)); verify(mockCacheFactory, never()).setPdxPersistent(any(Boolean.class)); verify(mockCacheFactory, times(1)).setPdxReadSerialized(eq(true)); verify(mockCacheFactory, times(1)).setPdxSerializer(any(PdxSerializer.class)); + + verifyNoMoreInteractions(mockCacheFactory); } @Test public void configureFactoryWithAllPdxOptions() { + CacheFactory mockCacheFactory = mock(CacheFactory.class); + CacheFactoryBean cacheFactoryBean = new CacheFactoryBean(); cacheFactoryBean.setPdxDiskStoreName("testPdxDiskStoreName"); @@ -541,15 +553,15 @@ public class CacheFactoryBeanTest { cacheFactoryBean.setPdxReadSerialized(true); cacheFactoryBean.setPdxSerializer(mock(PdxSerializer.class)); - CacheFactory mockCacheFactory = mock(CacheFactory.class); - - assertThat(cacheFactoryBean.configureFactory(mockCacheFactory), is(sameInstance(mockCacheFactory))); + assertThat(cacheFactoryBean.configureFactory(mockCacheFactory)).isSameAs(mockCacheFactory); verify(mockCacheFactory, times(1)).setPdxDiskStore(eq("testPdxDiskStoreName")); verify(mockCacheFactory, times(1)).setPdxIgnoreUnreadFields(eq(false)); verify(mockCacheFactory, times(1)).setPdxPersistent(eq(true)); verify(mockCacheFactory, times(1)).setPdxReadSerialized(eq(true)); verify(mockCacheFactory, times(1)).setPdxSerializer(any(PdxSerializer.class)); + + verifyNoMoreInteractions(mockCacheFactory); } @Test @@ -560,15 +572,18 @@ public class CacheFactoryBeanTest { org.apache.geode.security.SecurityManager mockSecurityManager = mock(org.apache.geode.security.SecurityManager.class); + doReturn(mockCacheFactory).when(mockCacheFactory).setSecurityManager(eq(mockSecurityManager)); + CacheFactoryBean cacheFactoryBean = new CacheFactoryBean(); cacheFactoryBean.setSecurityManager(mockSecurityManager); - assertThat(cacheFactoryBean.getSecurityManager(), is(sameInstance(mockSecurityManager))); - assertThat(cacheFactoryBean.configureFactory(mockCacheFactory), is(sameInstance(mockCacheFactory))); + assertThat(cacheFactoryBean.getSecurityManager()).isSameAs(mockSecurityManager); + assertThat(cacheFactoryBean.configureFactory(mockCacheFactory)).isSameAs(mockCacheFactory); verify(mockCacheFactory, times(1)).setSecurityManager(eq(mockSecurityManager)); - verifyZeroInteractions(mockSecurityManager); + verifyNoMoreInteractions(mockCacheFactory); + verifyNoInteractions(mockSecurityManager); } @Test @@ -576,35 +591,38 @@ public class CacheFactoryBeanTest { CacheFactory mockCacheFactory = mock(CacheFactory.class); - when(mockCacheFactory.create()).thenReturn(mockCache); + doReturn(this.mockCache).when(mockCacheFactory).create(); CacheFactoryBean cacheFactoryBean = new CacheFactoryBean(); Cache actualCache = cacheFactoryBean.createCache(mockCacheFactory); - assertThat(actualCache, is(equalTo(mockCache))); + assertThat(actualCache).isEqualTo(this.mockCache); verify(mockCacheFactory, times(1)).create(); - verifyZeroInteractions(mockCache); + verifyNoMoreInteractions(mockCacheFactory); + verifyNoInteractions(this.mockCache); } @Test(expected = IllegalArgumentException.class) public void postProcessCacheWithInvalidCriticalHeapPercentage() { try { + CacheFactoryBean cacheFactoryBean = new CacheFactoryBean(); cacheFactoryBean.setCriticalHeapPercentage(200.0f); - cacheFactoryBean.postProcess(mockCache); + cacheFactoryBean.postProcess(this.mockCache); } catch (IllegalArgumentException expected) { - assertEquals("criticalHeapPercentage [200.0] is not valid; must be >= 0.0 and <= 100.0", - expected.getMessage()); + + assertThat(expected).hasMessage("criticalHeapPercentage [200.0] is not valid; must be >= 0.0 and <= 100.0"); + assertThat(expected).hasNoCause(); throw expected; } finally { - verifyZeroInteractions(mockCache); + verifyNoInteractions(this.mockCache); } } @@ -612,19 +630,21 @@ public class CacheFactoryBeanTest { public void postProcessCacheWithInvalidCriticalOffHeapPercentage() { try { + CacheFactoryBean cacheFactoryBean = new CacheFactoryBean(); cacheFactoryBean.setCriticalOffHeapPercentage(200.0f); - cacheFactoryBean.postProcess(mockCache); + cacheFactoryBean.postProcess(this.mockCache); } catch (IllegalArgumentException expected) { - assertEquals("criticalOffHeapPercentage [200.0] is not valid; must be >= 0.0 and <= 100.0", - expected.getMessage()); + + assertThat(expected).hasMessage("criticalOffHeapPercentage [200.0] is not valid; must be >= 0.0 and <= 100.0"); + assertThat(expected).hasNoCause(); throw expected; } finally { - verifyZeroInteractions(mockCache); + verifyNoInteractions(this.mockCache); } } @@ -632,19 +652,21 @@ public class CacheFactoryBeanTest { public void postProcessCacheWithInvalidEvictionHeapPercentage() { try { + CacheFactoryBean cacheFactoryBean = new CacheFactoryBean(); cacheFactoryBean.setEvictionHeapPercentage(-75.0f); - cacheFactoryBean.postProcess(mockCache); + cacheFactoryBean.postProcess(this.mockCache); } catch (IllegalArgumentException expected) { - assertEquals("evictionHeapPercentage [-75.0] is not valid; must be >= 0.0 and <= 100.0", - expected.getMessage()); + + assertThat(expected).hasMessage("evictionHeapPercentage [-75.0] is not valid; must be >= 0.0 and <= 100.0"); + assertThat(expected).hasNoCause(); throw expected; } finally { - verifyZeroInteractions(mockCache); + verifyNoInteractions(this.mockCache); } } @@ -652,62 +674,59 @@ public class CacheFactoryBeanTest { public void postProcessCacheWithInvalidEvictionOffHeapPercentage() { try { + CacheFactoryBean cacheFactoryBean = new CacheFactoryBean(); cacheFactoryBean.setEvictionOffHeapPercentage(-75.0f); - cacheFactoryBean.postProcess(mockCache); + cacheFactoryBean.postProcess(this.mockCache); } catch (IllegalArgumentException expected) { - assertEquals("evictionOffHeapPercentage [-75.0] is not valid; must be >= 0.0 and <= 100.0", - expected.getMessage()); + + assertThat(expected).hasMessage("evictionOffHeapPercentage [-75.0] is not valid; must be >= 0.0 and <= 100.0"); + assertThat(expected).hasNoCause(); throw expected; } finally { - verifyZeroInteractions(mockCache); + verifyNoInteractions(this.mockCache); } } @Test - @SuppressWarnings("unchecked") - public void getObjectType() { - assertThat(new CacheFactoryBean().getObjectType(), is(equalTo(Cache.class))); + public void getObjectTypeEqualsCacheClass() { + assertThat(new CacheFactoryBean().getObjectType()).isEqualTo(Cache.class); } @Test - public void getObjectTypeWithExistingCache() { + public void getObjectTypeEqualsCacheInstanceType() { Cache mockCache = mock(Cache.class); + CacheFactoryBean cacheFactoryBean = new CacheFactoryBean(); cacheFactoryBean.setCache(mockCache); - assertThat(cacheFactoryBean.getObjectType(), is(equalTo((Class) mockCache.getClass()))); + assertThat(cacheFactoryBean.getCache()).isEqualTo(mockCache); + assertThat(cacheFactoryBean.getObjectType()).isEqualTo(mockCache.getClass()); } @Test public void isSingleton() { - assertTrue(new CacheFactoryBean().isSingleton()); + assertThat(new CacheFactoryBean().isSingleton()).isTrue(); } @Test - @SuppressWarnings("unchecked") public void destroy() throws Exception { - AtomicBoolean fetchCacheCalled = new AtomicBoolean(false); - Cache mockCache = mock(Cache.class, "GemFireCache"); - GemfireBeanFactoryLocator mockGemfireBeanFactoryLocator = mock(GemfireBeanFactoryLocator.class); - - when(mockCache.isClosed()).thenReturn(false); + doReturn(false).when(mockCache).isClosed(); CacheFactoryBean cacheFactoryBean = spy(new CacheFactoryBean()); - doAnswer(invocation -> { - fetchCacheCalled.set(true); - return mockCache; - }).when(cacheFactoryBean).fetchCache(); + doReturn(mockCache).when(cacheFactoryBean).fetchCache(); + + GemfireBeanFactoryLocator mockGemfireBeanFactoryLocator = mock(GemfireBeanFactoryLocator.class); doReturn(mockGemfireBeanFactoryLocator).when(cacheFactoryBean).getBeanFactoryLocator(); @@ -715,52 +734,70 @@ public class CacheFactoryBeanTest { cacheFactoryBean.setUseBeanFactoryLocator(true); cacheFactoryBean.destroy(); - assertThat(fetchCacheCalled.get(), is(true)); - + verify(cacheFactoryBean, times(1)).destroy(); + verify(cacheFactoryBean, times(1)).isClose(); + verify(cacheFactoryBean, times(1)).fetchCache(); + verify(cacheFactoryBean, times(1)).close(eq(mockCache)); + verify(cacheFactoryBean, times(1)).destroyBeanFactoryLocator(); verify(mockCache, times(1)).isClosed(); verify(mockCache, times(1)).close(); verify(mockGemfireBeanFactoryLocator, times(1)).destroy(); + + verifyNoMoreInteractions(mockCache, mockGemfireBeanFactoryLocator); } @Test - @SuppressWarnings("unchecked") - public void destroyWhenCacheIsNull() throws Exception { - - AtomicBoolean fetchCacheCalled = new AtomicBoolean(false); + public void destroyWhenCacheIsNull() { CacheFactoryBean cacheFactoryBean = spy(new CacheFactoryBean()); - doAnswer(invocation -> { - fetchCacheCalled.set(true); - return null; - }).when(cacheFactoryBean).fetchCache(); + doReturn(null).when(cacheFactoryBean).fetchCache(); cacheFactoryBean.setClose(true); cacheFactoryBean.setUseBeanFactoryLocator(true); cacheFactoryBean.destroy(); - assertTrue(fetchCacheCalled.get()); + verify(cacheFactoryBean, times(1)).destroy(); + verify(cacheFactoryBean, times(1)).isClose(); + verify(cacheFactoryBean, times(1)).fetchCache(); + verify(cacheFactoryBean, times(1)).close(isNull()); + verify(cacheFactoryBean, times(1)).destroyBeanFactoryLocator(); } @Test - @SuppressWarnings("unchecked") - public void destroyWhenCloseIsFalse() throws Exception { + public void destroyWhenCloseIsFalse() { - CacheFactoryBean cacheFactoryBean = new CacheFactoryBean(); + CacheFactoryBean cacheFactoryBean = spy(new CacheFactoryBean()); cacheFactoryBean.setClose(false); cacheFactoryBean.setUseBeanFactoryLocator(false); cacheFactoryBean.destroy(); + + verify(cacheFactoryBean, times(1)).isClose(); + verify(cacheFactoryBean, never()).fetchCache(); + verify(cacheFactoryBean, never()).close(any()); + verify(cacheFactoryBean, never()).destroyBeanFactoryLocator(); } @Test public void closeCache() { - GemFireCache mockCache = mock(GemFireCache.class, "testCloseCache.MockCache"); + GemFireCache mockCache = mock(GemFireCache.class); - new CacheFactoryBean().close(mockCache); + CacheFactoryBean cacheFactoryBean = new CacheFactoryBean(); + cacheFactoryBean.setCache(mockCache); + + assertThat(cacheFactoryBean.getCache()).isEqualTo(mockCache); + + cacheFactoryBean.close(mockCache); + + assertThat(cacheFactoryBean.getCache()).isNull(); + + verify(mockCache, times(1)).isClosed(); verify(mockCache, times(1)).close(); + + verifyNoMoreInteractions(mockCache); } @Test @@ -769,15 +806,19 @@ public class CacheFactoryBeanTest { BeanFactory mockBeanFactory = mock(BeanFactory.class, "SpringBeanFactory"); - GatewayConflictResolver mockGatewayConflictResolver = mock(GatewayConflictResolver.class, "GemFireGatewayConflictResolver"); + GatewayConflictResolver mockGatewayConflictResolver = + mock(GatewayConflictResolver.class, "GemFireGatewayConflictResolver"); - PdxSerializer mockPdxSerializer = mock(PdxSerializer.class, "GemFirePdxSerializer"); + PdxSerializer mockPdxSerializer = + mock(PdxSerializer.class, "GemFirePdxSerializer"); Resource mockCacheXml = mock(Resource.class, "GemFireCacheXml"); - TransactionListener mockTransactionListener = mock(TransactionListener.class, "GemFireTransactionListener"); + TransactionListener mockTransactionListener = + mock(TransactionListener.class, "GemFireTransactionListener"); - TransactionWriter mockTransactionWriter = mock(TransactionWriter.class, "GemFireTransactionWriter"); + TransactionWriter mockTransactionWriter = + mock(TransactionWriter.class, "GemFireTransactionWriter"); Properties gemfireProperties = new Properties(); @@ -811,36 +852,36 @@ public class CacheFactoryBeanTest { cacheFactoryBean.setTransactionWriter(mockTransactionWriter); cacheFactoryBean.setUseClusterConfiguration(true); - assertEquals(Thread.currentThread().getContextClassLoader(), cacheFactoryBean.getBeanClassLoader()); - assertSame(mockBeanFactory, cacheFactoryBean.getBeanFactory()); - assertNull(cacheFactoryBean.getBeanFactoryLocator()); - assertEquals("TestCache", cacheFactoryBean.getBeanName()); - assertSame(mockCacheXml, cacheFactoryBean.getCacheXml()); - assertSame(gemfireProperties, cacheFactoryBean.getProperties()); - assertTrue(Boolean.FALSE.equals(TestUtils.readField("useBeanFactoryLocator", cacheFactoryBean))); - assertTrue(Boolean.FALSE.equals(TestUtils.readField("close", cacheFactoryBean))); - assertTrue(cacheFactoryBean.getCopyOnRead()); - assertEquals(0.95f, cacheFactoryBean.getCriticalHeapPercentage(), 0.0f); - assertEquals(0.99f, cacheFactoryBean.getCriticalOffHeapPercentage(), 0.0f); - assertTrue(cacheFactoryBean.getEnableAutoReconnect()); - assertEquals(0.70f, cacheFactoryBean.getEvictionHeapPercentage(), 0.0f); - assertEquals(0.80f, cacheFactoryBean.getEvictionOffHeapPercentage(), 0.0f); - assertSame(mockGatewayConflictResolver, cacheFactoryBean.getGatewayConflictResolver()); - assertNotNull(cacheFactoryBean.getJndiDataSources()); - assertEquals(1, cacheFactoryBean.getJndiDataSources().size()); - assertEquals(15000, cacheFactoryBean.getLockLease().intValue()); - assertEquals(5000, cacheFactoryBean.getLockTimeout().intValue()); - assertEquals(10000, cacheFactoryBean.getMessageSyncInterval().intValue()); - assertSame(mockPdxSerializer, cacheFactoryBean.getPdxSerializer()); - assertFalse(cacheFactoryBean.getPdxReadSerialized()); - assertTrue(cacheFactoryBean.getPdxPersistent()); - assertTrue(cacheFactoryBean.getPdxIgnoreUnreadFields()); - assertEquals("TestPdxDiskStore", cacheFactoryBean.getPdxDiskStoreName()); - assertEquals(30000, cacheFactoryBean.getSearchTimeout().intValue()); - assertNotNull(cacheFactoryBean.getTransactionListeners()); - assertEquals(1, cacheFactoryBean.getTransactionListeners().size()); - assertSame(mockTransactionListener, cacheFactoryBean.getTransactionListeners().get(0)); - assertSame(mockTransactionWriter, cacheFactoryBean.getTransactionWriter()); - assertTrue(cacheFactoryBean.getUseClusterConfiguration()); + assertThat(cacheFactoryBean.getBeanClassLoader()).isEqualTo(Thread.currentThread().getContextClassLoader()); + assertThat(cacheFactoryBean.getBeanFactory()).isSameAs(mockBeanFactory); + assertThat(cacheFactoryBean.getBeanFactoryLocator()).isNull(); + assertThat(cacheFactoryBean.getBeanName()).isEqualTo("TestCache"); + assertThat(cacheFactoryBean.getCacheXml()).isSameAs(mockCacheXml); + assertThat(cacheFactoryBean.getProperties()).isSameAs(gemfireProperties); + assertThat(Boolean.FALSE.equals(TestUtils.readField("useBeanFactoryLocator", cacheFactoryBean))).isTrue(); + assertThat(Boolean.FALSE.equals(TestUtils.readField("close", cacheFactoryBean))).isTrue(); + assertThat(cacheFactoryBean.getCopyOnRead()).isTrue(); + assertThat(cacheFactoryBean.getCriticalHeapPercentage()).isCloseTo(0.95f, offset(0.0f)); + assertThat(cacheFactoryBean.getCriticalOffHeapPercentage()).isCloseTo(0.99f, offset(0.0f)); + assertThat(cacheFactoryBean.getEnableAutoReconnect()).isTrue(); + assertThat(cacheFactoryBean.getEvictionHeapPercentage()).isCloseTo(0.70f, offset(0.0f)); + assertThat(cacheFactoryBean.getEvictionOffHeapPercentage()).isCloseTo(0.80f, offset(0.0f)); + assertThat(cacheFactoryBean.getGatewayConflictResolver()).isSameAs(mockGatewayConflictResolver); + assertThat(cacheFactoryBean.getJndiDataSources()).isNotNull(); + assertThat(cacheFactoryBean.getJndiDataSources().size()).isEqualTo(1); + assertThat(cacheFactoryBean.getLockLease().intValue()).isEqualTo(15000); + assertThat(cacheFactoryBean.getLockTimeout().intValue()).isEqualTo(5000); + assertThat(cacheFactoryBean.getMessageSyncInterval().intValue()).isEqualTo(10000); + assertThat(cacheFactoryBean.getPdxSerializer()).isSameAs(mockPdxSerializer); + assertThat(cacheFactoryBean.getPdxReadSerialized()).isFalse(); + assertThat(cacheFactoryBean.getPdxPersistent()).isTrue(); + assertThat(cacheFactoryBean.getPdxIgnoreUnreadFields()).isTrue(); + assertThat(cacheFactoryBean.getPdxDiskStoreName()).isEqualTo("TestPdxDiskStore"); + assertThat(cacheFactoryBean.getSearchTimeout().intValue()).isEqualTo(30000); + assertThat(cacheFactoryBean.getTransactionListeners()).isNotNull(); + assertThat(cacheFactoryBean.getTransactionListeners().size()).isEqualTo(1); + assertThat(cacheFactoryBean.getTransactionListeners().get(0)).isSameAs(mockTransactionListener); + assertThat(cacheFactoryBean.getTransactionWriter()).isSameAs(mockTransactionWriter); + assertThat(cacheFactoryBean.getUseClusterConfiguration()).isTrue(); } } diff --git a/spring-data-geode/src/test/java/org/springframework/data/gemfire/client/ClientCacheFactoryBeanTest.java b/spring-data-geode/src/test/java/org/springframework/data/gemfire/client/ClientCacheFactoryBeanUnitTests.java similarity index 93% rename from spring-data-geode/src/test/java/org/springframework/data/gemfire/client/ClientCacheFactoryBeanTest.java rename to spring-data-geode/src/test/java/org/springframework/data/gemfire/client/ClientCacheFactoryBeanUnitTests.java index 5fab7eed..63b92d11 100644 --- a/spring-data-geode/src/test/java/org/springframework/data/gemfire/client/ClientCacheFactoryBeanTest.java +++ b/spring-data-geode/src/test/java/org/springframework/data/gemfire/client/ClientCacheFactoryBeanUnitTests.java @@ -21,6 +21,7 @@ import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isA; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; @@ -29,13 +30,14 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import java.net.InetSocketAddress; import java.util.Arrays; import java.util.Collections; -import java.util.Optional; import java.util.Properties; +import java.util.function.Supplier; import org.junit.Test; @@ -73,7 +75,7 @@ import org.springframework.data.gemfire.util.DistributedSystemUtils; * @see org.springframework.data.gemfire.client.ClientCacheFactoryBean * @since 1.7.0 */ -public class ClientCacheFactoryBeanTest { +public class ClientCacheFactoryBeanUnitTests { private Properties createProperties(String key, String value) { return addProperty(null, key, value); @@ -81,7 +83,7 @@ public class ClientCacheFactoryBeanTest { private Properties addProperty(Properties properties, String key, String value) { - properties = Optional.ofNullable(properties).orElseGet(Properties::new); + properties = properties != null ? properties : new Properties(); properties.setProperty(key, value); return properties; @@ -101,12 +103,13 @@ public class ClientCacheFactoryBeanTest { ClientCache mockClientCache = mock(ClientCache.class); - ClientCacheFactoryBean clientCacheFactoryBean = new ClientCacheFactoryBean(); + ClientCacheFactoryBean clientCacheFactoryBean = spy(new ClientCacheFactoryBean()); - clientCacheFactoryBean.setCache(mockClientCache); + doReturn(mockClientCache).when(clientCacheFactoryBean).getCache(); assertThat(clientCacheFactoryBean.getObjectType()).isNotEqualTo(ClientCache.class); assertThat(clientCacheFactoryBean.getObjectType()).isEqualTo(mockClientCache.getClass()); + assertThat(ClientCache.class).isAssignableFrom(clientCacheFactoryBean.getObjectType()); } @Test @@ -114,6 +117,24 @@ public class ClientCacheFactoryBeanTest { assertThat(new ClientCacheFactoryBean().isSingleton()).isTrue(); } + @Test + @SuppressWarnings("unchecked") + public void resolvePropertiesCallsResolvePropertiesWithSupplier() { + + ClientCacheFactoryBean clientCacheFactoryBean = spy(new ClientCacheFactoryBean()); + + Properties properties = createProperties("key", "test"); + + doReturn(properties).when(clientCacheFactoryBean).resolveProperties(isA(Supplier.class)); + + assertThat(clientCacheFactoryBean.resolveProperties()).isEqualTo(properties); + + verify(clientCacheFactoryBean, times(1)).resolveProperties(); + verify(clientCacheFactoryBean, times(1)).resolveProperties(isA(Supplier.class)); + + verifyNoMoreInteractions(clientCacheFactoryBean); + } + @Test public void resolvePropertiesWhenDistributedSystemIsConnected() { @@ -122,64 +143,63 @@ public class ClientCacheFactoryBeanTest { DistributedSystem mockDistributedSystem = mock(DistributedSystem.class); - when(mockDistributedSystem.isConnected()).thenReturn(true); - when(mockDistributedSystem.getProperties()).thenReturn(distributedSystemProperties); + doReturn(true).when(mockDistributedSystem).isConnected(); + doReturn(distributedSystemProperties).when(mockDistributedSystem).getProperties(); ClientCacheFactoryBean clientCacheFactoryBean = spy(new ClientCacheFactoryBean()); - doReturn(mockDistributedSystem).when(clientCacheFactoryBean).getDistributedSystem(); - clientCacheFactoryBean.setProperties(gemfireProperties); - Properties resolvedProperties = clientCacheFactoryBean.resolveProperties(); + Properties resolvedProperties = clientCacheFactoryBean.resolveProperties(() -> mockDistributedSystem); assertThat(resolvedProperties).isNotNull(); assertThat(resolvedProperties).isNotSameAs(gemfireProperties); assertThat(resolvedProperties).isNotSameAs(distributedSystemProperties); - assertThat(resolvedProperties.size()).isEqualTo(2); assertThat(resolvedProperties.containsKey(DistributedSystemUtils.DURABLE_CLIENT_ID_PROPERTY_NAME)).isFalse(); - assertThat(resolvedProperties.containsKey(DistributedSystemUtils.DURABLE_CLIENT_TIMEOUT_PROPERTY_NAME)) - .isFalse(); + assertThat(resolvedProperties.containsKey(DistributedSystemUtils.DURABLE_CLIENT_TIMEOUT_PROPERTY_NAME)).isFalse(); assertThat(resolvedProperties.getProperty("gf")).isEqualTo("test"); assertThat(resolvedProperties.getProperty("ds")).isEqualTo("mock"); + assertThat(resolvedProperties.size()).isEqualTo(2); verify(mockDistributedSystem, times(1)).isConnected(); verify(mockDistributedSystem, times(1)).getProperties(); + + verifyNoMoreInteractions(mockDistributedSystem); } @Test public void resolvePropertiesWhenDistributedSystemIsConnectedAndClientIsDurable() { - Properties gemfireProperties = DistributedSystemUtils.configureDurableClient( - createProperties("gf", "test"), "123", 600); + Properties gemfireProperties = DistributedSystemUtils + .configureDurableClient(createProperties("gf", "test"), "123", 600); - Properties distributedSystemProperties = DistributedSystemUtils.configureDurableClient( - createProperties("ds", "mock"), "987", 300); + Properties distributedSystemProperties = DistributedSystemUtils + .configureDurableClient(createProperties("ds", "mock"), "987", 300); DistributedSystem mockDistributedSystem = mock(DistributedSystem.class); - when(mockDistributedSystem.isConnected()).thenReturn(true); - when(mockDistributedSystem.getProperties()).thenReturn(distributedSystemProperties); + doReturn(true).when(mockDistributedSystem).isConnected(); + doReturn(distributedSystemProperties).when(mockDistributedSystem).getProperties(); ClientCacheFactoryBean clientCacheFactoryBean = spy(new ClientCacheFactoryBean()); - doReturn(mockDistributedSystem).when(clientCacheFactoryBean).getDistributedSystem(); - clientCacheFactoryBean.setProperties(gemfireProperties); - Properties resolvedProperties = clientCacheFactoryBean.resolveProperties(); + Properties resolvedProperties = clientCacheFactoryBean.resolveProperties(() -> mockDistributedSystem); assertThat(resolvedProperties).isNotNull(); assertThat(resolvedProperties).isNotSameAs(gemfireProperties); assertThat(resolvedProperties).isNotSameAs(distributedSystemProperties); - assertThat(resolvedProperties.size()).isEqualTo(4); assertThat(resolvedProperties.getProperty("gf")).isEqualTo("test"); assertThat(resolvedProperties.getProperty("ds")).isEqualTo("mock"); assertThat(resolvedProperties.getProperty(DistributedSystemUtils.DURABLE_CLIENT_ID_PROPERTY_NAME)).isEqualTo("123"); assertThat(resolvedProperties.getProperty(DistributedSystemUtils.DURABLE_CLIENT_TIMEOUT_PROPERTY_NAME)).isEqualTo("600"); + assertThat(resolvedProperties.size()).isEqualTo(4); verify(mockDistributedSystem, times(1)).isConnected(); verify(mockDistributedSystem, times(1)).getProperties(); + + verifyNoMoreInteractions(mockDistributedSystem); } @Test @@ -190,21 +210,21 @@ public class ClientCacheFactoryBeanTest { DistributedSystem mockDistributedSystem = mock(DistributedSystem.class); - when(mockDistributedSystem.isConnected()).thenReturn(false); - when(mockDistributedSystem.getProperties()).thenReturn(distributedSystemProperties); + doReturn(false).when(mockDistributedSystem).isConnected(); + doReturn(distributedSystemProperties).when(mockDistributedSystem).getProperties(); ClientCacheFactoryBean clientCacheFactoryBean = spy(new ClientCacheFactoryBean()); - doReturn(mockDistributedSystem).when(clientCacheFactoryBean).getDistributedSystem(); - clientCacheFactoryBean.setProperties(gemfireProperties); - Properties resolvedProperties = clientCacheFactoryBean.resolveProperties(); + Properties resolvedProperties = clientCacheFactoryBean.resolveProperties(() -> mockDistributedSystem); assertThat(resolvedProperties).isSameAs(gemfireProperties); verify(mockDistributedSystem, times(1)).isConnected(); verify(mockDistributedSystem, never()).getProperties(); + + verifyNoMoreInteractions(mockDistributedSystem); } @Test @@ -212,22 +232,17 @@ public class ClientCacheFactoryBeanTest { Properties gemfireProperties = createProperties("gf", "test"); - assertThat(gemfireProperties.size()).isEqualTo(1); - ClientCacheFactoryBean clientCacheFactoryBean = spy(new ClientCacheFactoryBean()); - doReturn(null).when(clientCacheFactoryBean).getDistributedSystem(); - clientCacheFactoryBean.setDurableClientId("123"); clientCacheFactoryBean.setProperties(gemfireProperties); - Properties resolvedProperties = clientCacheFactoryBean.resolveProperties(); + Properties resolvedProperties = clientCacheFactoryBean.resolveProperties(() -> null); assertThat(resolvedProperties).isSameAs(gemfireProperties); - assertThat(resolvedProperties.size()).isEqualTo(2); assertThat(resolvedProperties.getProperty("gf")).isEqualTo("test"); - assertThat(resolvedProperties.getProperty(DistributedSystemUtils.DURABLE_CLIENT_ID_PROPERTY_NAME)) - .isEqualTo("123"); + assertThat(resolvedProperties.getProperty(DistributedSystemUtils.DURABLE_CLIENT_ID_PROPERTY_NAME)).isEqualTo("123"); + assertThat(resolvedProperties.size()).isEqualTo(2); } @Test @@ -242,14 +257,14 @@ public class ClientCacheFactoryBeanTest { ClientCacheFactory clientCacheFactory = (ClientCacheFactory) clientCacheFactoryReference; - clientCacheFactory.set("testCase", "TestCreateClientCacheFactory"); + clientCacheFactory.set("testKey", "testValue"); - assertThat(gemfireProperties.containsKey("testCase")).isTrue(); - assertThat(gemfireProperties.getProperty("testCase")).isEqualTo("TestCreateClientCacheFactory"); + assertThat(gemfireProperties.containsKey("testKey")).isTrue(); + assertThat(gemfireProperties.getProperty("testKey")).isEqualTo("testValue"); } @Test - public void prepareClientCacheFactoryCallsInitializePdxAndInitializePool() { + public void configureClientCacheFactoryCallsConfigurePdxAndConfigurePool() { ClientCacheFactory mockClientCacheFactory = mock(ClientCacheFactory.class); @@ -260,12 +275,17 @@ public class ClientCacheFactoryBeanTest { assertThat(clientCacheFactoryBean.configureFactory(mockClientCacheFactory)).isSameAs(mockClientCacheFactory); + verify(clientCacheFactoryBean, times(1)).configureFactory(eq(mockClientCacheFactory)); verify(clientCacheFactoryBean, times(1)).configurePdx(eq(mockClientCacheFactory)); verify(clientCacheFactoryBean, times(1)).configurePool(eq(mockClientCacheFactory)); + + verifyNoMoreInteractions(mockClientCacheFactory); } @Test - public void initializePdxWithAllPdxOptions() { + public void configurePdxWithAllPdxOptions() { + + ClientCacheFactory mockClientCacheFactory = mock(ClientCacheFactory.class); ClientCacheFactoryBean clientCacheFactoryBean = new ClientCacheFactoryBean(); @@ -283,8 +303,6 @@ public class ClientCacheFactoryBeanTest { assertThat(clientCacheFactoryBean.getPdxReadSerialized()).isFalse(); assertThat(clientCacheFactoryBean.getPdxSerializer()).isSameAs(mockPdxSerializer); - ClientCacheFactory mockClientCacheFactory = mock(ClientCacheFactory.class); - assertThat(clientCacheFactoryBean.configurePdx(mockClientCacheFactory)).isSameAs(mockClientCacheFactory); verify(mockClientCacheFactory, times(1)).setPdxSerializer(eq(mockPdxSerializer)); @@ -292,10 +310,14 @@ public class ClientCacheFactoryBeanTest { verify(mockClientCacheFactory, times(1)).setPdxIgnoreUnreadFields(eq(false)); verify(mockClientCacheFactory, times(1)).setPdxPersistent(eq(true)); verify(mockClientCacheFactory, times(1)).setPdxReadSerialized(eq(false)); + + verifyNoMoreInteractions(mockClientCacheFactory); } @Test - public void initializePdxWithPartialPdxOptions() { + public void configurePdxWithPartialPdxOptions() { + + ClientCacheFactory mockClientCacheFactory = mock(ClientCacheFactory.class); ClientCacheFactoryBean clientCacheFactoryBean = new ClientCacheFactoryBean(); @@ -308,8 +330,6 @@ public class ClientCacheFactoryBeanTest { assertThat(clientCacheFactoryBean.getPdxReadSerialized()).isTrue(); assertThat(clientCacheFactoryBean.getPdxSerializer()).isNull(); - ClientCacheFactory mockClientCacheFactory = mock(ClientCacheFactory.class); - assertThat(clientCacheFactoryBean.configurePdx(mockClientCacheFactory)).isSameAs(mockClientCacheFactory); verify(mockClientCacheFactory, never()).setPdxDiskStore(anyString()); @@ -317,10 +337,14 @@ public class ClientCacheFactoryBeanTest { verify(mockClientCacheFactory, never()).setPdxPersistent(anyBoolean()); verify(mockClientCacheFactory, times(1)).setPdxReadSerialized(eq(true)); verify(mockClientCacheFactory, never()).setPdxSerializer(any(PdxSerializer.class)); + + verifyNoMoreInteractions(mockClientCacheFactory); } @Test - public void initializePdxWithNoPdxOptions() { + public void configurePdxWithNoPdxOptions() { + + ClientCacheFactory mockClientCacheFactory = mock(ClientCacheFactory.class); ClientCacheFactoryBean clientCacheFactoryBean = new ClientCacheFactoryBean(); @@ -330,15 +354,13 @@ public class ClientCacheFactoryBeanTest { assertThat(clientCacheFactoryBean.getPdxReadSerialized()).isNull(); assertThat(clientCacheFactoryBean.getPdxSerializer()).isNull(); - ClientCacheFactory mockClientCacheFactory = mock(ClientCacheFactory.class); - assertThat(clientCacheFactoryBean.configurePdx(mockClientCacheFactory)).isSameAs(mockClientCacheFactory); verifyNoInteractions(mockClientCacheFactory); } @Test - public void initializePoolWithClientCacheFactoryBean() { + public void configurePoolWithClientCacheFactoryBean() { Pool mockPool = mock(Pool.class); @@ -429,7 +451,7 @@ public class ClientCacheFactoryBeanTest { } @Test - public void initializePoolWithPool() { + public void configurePoolWithPool() { Pool mockPool = mock(Pool.class); @@ -544,7 +566,7 @@ public class ClientCacheFactoryBeanTest { } @Test - public void initializePoolWithClientCacheFactoryBeanAndPoolButClientCacheFactoryBeanOverridesPool() { + public void configurePoolWithClientCacheFactoryBeanAndPoolButClientCacheFactoryBeanOverridesPool() { Pool mockPool = mock(Pool.class); @@ -672,7 +694,7 @@ public class ClientCacheFactoryBeanTest { } @Test - public void initializePoolWithFactoryLocator() { + public void configurePoolWithFactoryLocator() { Pool mockPool = mock(Pool.class); @@ -699,7 +721,7 @@ public class ClientCacheFactoryBeanTest { } @Test - public void initializePoolWithFactoryServer() { + public void configurePoolWithFactoryServer() { Pool mockPool = mock(Pool.class); @@ -726,7 +748,7 @@ public class ClientCacheFactoryBeanTest { } @Test - public void initializePoolWithPoolLocator() { + public void configurePoolWithPoolLocator() { Pool mockPool = mock(Pool.class); @@ -752,7 +774,7 @@ public class ClientCacheFactoryBeanTest { } @Test - public void initializePoolWithPoolServer() { + public void configurePoolWithPoolServer() { Pool mockPool = mock(Pool.class); @@ -778,7 +800,7 @@ public class ClientCacheFactoryBeanTest { } @Test - public void initializePoolWithDefaultServer() { + public void configurePoolWithDefaultServer() { ClientCacheFactoryBean clientCacheFactoryBean = spy(new ClientCacheFactoryBean()); @@ -804,13 +826,14 @@ public class ClientCacheFactoryBeanTest { ClientCacheFactory mockClientCacheFactory = mock(ClientCacheFactory.class); - when(mockClientCacheFactory.create()).thenReturn(mockClientCache); + doReturn(mockClientCache).when(mockClientCacheFactory).create(); ClientCacheFactoryBean clientCacheFactoryBean = new ClientCacheFactoryBean(); assertThat(clientCacheFactoryBean.createCache(mockClientCacheFactory)).isSameAs(mockClientCache); verify(mockClientCacheFactory, times(1)).create(); + verifyNoMoreInteractions(mockClientCacheFactory); verifyNoInteractions(mockClientCache); } @@ -907,7 +930,7 @@ public class ClientCacheFactoryBeanTest { ClientCacheFactoryBean clientCacheFactoryBean = spy(new ClientCacheFactoryBean()); - doReturn(mockClientCache).when(clientCacheFactoryBean).fetchCache(); + doReturn(mockClientCache).when(clientCacheFactoryBean).getCache(); clientCacheFactoryBean.setReadyForEvents(true); @@ -927,7 +950,7 @@ public class ClientCacheFactoryBeanTest { ClientCacheFactoryBean clientCacheFactoryBean = spy(new ClientCacheFactoryBean()); - doReturn(mockClientCache).when(clientCacheFactoryBean).fetchCache(); + doReturn(mockClientCache).when(clientCacheFactoryBean).getCache(); clientCacheFactoryBean.setReadyForEvents(false); @@ -947,7 +970,7 @@ public class ClientCacheFactoryBeanTest { ClientCacheFactoryBean clientCacheFactoryBean = spy(new ClientCacheFactoryBean()); - doReturn(mockClientCache).when(clientCacheFactoryBean).fetchCache(); + doReturn(mockClientCache).when(clientCacheFactoryBean).getCache(); clientCacheFactoryBean.setReadyForEvents(true); @@ -963,7 +986,7 @@ public class ClientCacheFactoryBeanTest { ClientCacheFactoryBean clientCacheFactoryBean = spy(new ClientCacheFactoryBean()); - doThrow(new CacheClosedException("test")).when(clientCacheFactoryBean).fetchCache(); + doThrow(new CacheClosedException("test")).when(clientCacheFactoryBean).getCache(); clientCacheFactoryBean.setReadyForEvents(true); @@ -1188,7 +1211,7 @@ public class ClientCacheFactoryBeanTest { ClientCacheFactoryBean clientCacheFactoryBean = spy(new ClientCacheFactoryBean()); - doReturn(mockClientCache).when(clientCacheFactoryBean).fetchCache(); + doReturn(mockClientCache).when(clientCacheFactoryBean).getCache(); clientCacheFactoryBean.setReadyForEvents(true); @@ -1205,7 +1228,7 @@ public class ClientCacheFactoryBeanTest { ClientCacheFactoryBean clientCacheFactoryBean = spy(new ClientCacheFactoryBean()); - doReturn(mockClientCache).when(clientCacheFactoryBean).fetchCache(); + doReturn(mockClientCache).when(clientCacheFactoryBean).getCache(); clientCacheFactoryBean.setReadyForEvents(false); @@ -1220,7 +1243,7 @@ public class ClientCacheFactoryBeanTest { ClientCacheFactoryBean clientCacheFactoryBean = spy(new ClientCacheFactoryBean()); - doThrow(new CacheClosedException("test")).when(clientCacheFactoryBean).fetchCache(); + doThrow(new CacheClosedException("test")).when(clientCacheFactoryBean).getCache(); assertThat(clientCacheFactoryBean.getReadyForEvents()).isNull(); assertThat(clientCacheFactoryBean.isReadyForEvents()).isFalse(); @@ -1233,7 +1256,7 @@ public class ClientCacheFactoryBeanTest { ClientCacheFactoryBean clientCacheFactoryBean = spy(new ClientCacheFactoryBean()); - doReturn(mockClientCache).when(clientCacheFactoryBean).fetchCache(); + doReturn(mockClientCache).when(clientCacheFactoryBean).getCache(); assertThat(clientCacheFactoryBean.getReadyForEvents()).isNull(); assertThat(clientCacheFactoryBean.isReadyForEvents()).isTrue(); @@ -1248,7 +1271,7 @@ public class ClientCacheFactoryBeanTest { ClientCacheFactoryBean clientCacheFactoryBean = spy(new ClientCacheFactoryBean()); - doReturn(mockClientCache).when(clientCacheFactoryBean).fetchCache(); + doReturn(mockClientCache).when(clientCacheFactoryBean).getCache(); assertThat(clientCacheFactoryBean.getReadyForEvents()).isNull(); assertThat(clientCacheFactoryBean.isReadyForEvents()).isFalse(); diff --git a/spring-data-geode/src/test/java/org/springframework/data/gemfire/test/MockClientCacheFactoryBean.java b/spring-data-geode/src/test/java/org/springframework/data/gemfire/test/MockClientCacheFactoryBean.java index afba3419..06562f3a 100644 --- a/spring-data-geode/src/test/java/org/springframework/data/gemfire/test/MockClientCacheFactoryBean.java +++ b/spring-data-geode/src/test/java/org/springframework/data/gemfire/test/MockClientCacheFactoryBean.java @@ -30,9 +30,9 @@ public class MockClientCacheFactoryBean extends ClientCacheFactoryBean { setUseBeanFactoryLocator(false); Optional.ofNullable(clientCacheFactoryBean).ifPresent(it -> { - this.beanFactoryLocator = it.getBeanFactoryLocator(); setBeanClassLoader(it.getBeanClassLoader()); setBeanFactory(it.getBeanFactory()); + setBeanFactoryLocator(it.getBeanFactoryLocator()); setBeanName(it.getBeanName()); setCacheXml(it.getCacheXml()); setCopyOnRead(it.getCopyOnRead());