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 index a6cfeb35..2bdbe00c 100644 --- 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 @@ -15,16 +15,9 @@ */ 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.List; import java.util.Objects; import java.util.Optional; -import java.util.Properties; import java.util.function.Function; import org.apache.geode.GemFireCheckedException; @@ -40,12 +33,10 @@ import org.apache.geode.cache.client.ClientCache; import org.apache.geode.cache.client.ClientCacheFactory; import org.apache.geode.pdx.PdxSerializer; -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; @@ -53,7 +44,6 @@ 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.data.gemfire.util.CollectionUtils; import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; @@ -67,44 +57,48 @@ import org.springframework.util.StringUtils; * 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. + * the presence of this class automatically enables Spring's {@link PersistenceExceptionTranslationPostProcessor} + * to translate Apache Geode thrown {@link GemFireException} and {@link GemFireCheckedException} types + * as Spring {@link DataAccessException DataAccessExceptions}. * - * Importantly, this abstract class encapsulates configuration applicable to tuning Apache Geode to efficiently use JVM - * Heap memory. Since Apache Geode stores data in-memory, on the JVM Heap, it is important that Apache 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. + * More importantly, this abstract class encapsulates configuration applicable to tuning Apache Geode in order to + * efficiently use JVM Heap memory. Since Apache Geode stores data in-memory, on the JVM Heap, it is important that + * Apache Geode be tuned to monitor the JVM Heap and respond to memory pressure accordingly, by evicting data + * and issuing warnings when the JVM Heap reaches critical mass. + * + * This abstract class is also concerned with the configuration of PDX and transaction event handling along with + * whether the contents (entries) of the cache should be made effectively immutable on reads (i.e. get(key)). * * @author John Blum - * @see java.io.File - * @see java.util.Properties + * @see org.apache.geode.GemFireCheckedException + * @see org.apache.geode.GemFireException * @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.TransactionListener + * @see org.apache.geode.cache.TransactionWriter * @see org.apache.geode.cache.client.ClientCache * @see org.apache.geode.cache.client.ClientCacheFactory - * @see org.springframework.beans.factory.BeanFactory + * @see org.apache.geode.pdx.PdxSerializer * @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.annotation.PersistenceExceptionTranslationPostProcessor * @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; @@ -120,44 +114,16 @@ public abstract class AbstractBasicCacheFactoryBean extends AbstractFactoryBeanS private Float evictionHeapPercentage; private Float evictionOffHeapPercentage; - private GemfireBeanFactoryLocator beanFactoryLocator; - private GemFireCache cache; private List transactionListeners; private PdxSerializer pdxSerializer; - private Properties properties; - - private Resource cacheXml; - private String pdxDiskStoreName; private TransactionWriter transactionWriter; - /** - * 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}. @@ -219,62 +185,6 @@ public abstract class AbstractBasicCacheFactoryBean extends AbstractFactoryBeanS 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()); - } - } - /** * Sets a boolean value used to determine whether the cache should be closed on shutdown of the Spring application. * @@ -406,9 +316,9 @@ public abstract class AbstractBasicCacheFactoryBean extends AbstractFactoryBeanS protected abstract GemFireCache doGetObject(); /** - * Returns the {@link Class type} of {@link GemFireCache} produced by this cache {@link FactoryBean}. + * Returns the {@link Class type} of {@link GemFireCache} created by this cache {@link FactoryBean}. * - * @return the {@link Class type} type of {@link GemFireCache} produced by this cache {@link FactoryBean}. + * @return the {@link Class type} type of {@link GemFireCache} created by this cache {@link FactoryBean}. * @see org.springframework.beans.factory.FactoryBean#getObjectType() */ @Override @@ -419,6 +329,13 @@ public abstract class AbstractBasicCacheFactoryBean extends AbstractFactoryBeanS return cache != null ? cache.getClass() : doGetObjectType(); } + /** + * By default, returns {@link GemFireCache} {@link Class}. + * + * @return {@link GemFireCache} {@link Class} by default. + * @see org.apache.geode.cache.GemFireCache#getClass() + * @see java.lang.Class + */ protected Class doGetObjectType() { return GemFireCache.class; } @@ -562,40 +479,6 @@ public abstract class AbstractBasicCacheFactoryBean extends AbstractFactoryBeanS 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; - } - /** * Configures the cache (transaction manager) with a {@link List} of {@link TransactionListener TransactionListeners} * implemented by applications to listen for and receive transaction events after a transaction is processed @@ -605,7 +488,7 @@ public abstract class AbstractBasicCacheFactoryBean extends AbstractFactoryBeanS * registered with the cache to listen for and receive transaction events. * @see org.apache.geode.cache.TransactionListener */ - public void setTransactionListeners(@NonNull List transactionListeners) { + public void setTransactionListeners(List transactionListeners) { this.transactionListeners = transactionListeners; } @@ -618,7 +501,7 @@ public abstract class AbstractBasicCacheFactoryBean extends AbstractFactoryBeanS * the cache (transaction manager) to listen for and receive transaction events. * @see org.apache.geode.cache.TransactionListener */ - public @NonNull List getTransactionListeners() { + public List getTransactionListeners() { return CollectionUtils.nullSafeList(this.transactionListeners); } @@ -643,26 +526,6 @@ public abstract class AbstractBasicCacheFactoryBean extends AbstractFactoryBeanS return this.transactionWriter; } - /** - * 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; - } - - /** - * 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; - } - /** * Initializes this cache {@link FactoryBean} after all properties for this cache bean have been set * by the Spring container. @@ -670,12 +533,10 @@ public abstract class AbstractBasicCacheFactoryBean extends AbstractFactoryBeanS * @throws Exception if initialization fails. * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() * @see #applyCacheConfigurers() - * @see #initBeanFactoryLocator() */ @Override public void afterPropertiesSet() throws Exception { applyCacheConfigurers(); - initBeanFactoryLocator(); } /** @@ -705,8 +566,8 @@ public abstract class AbstractBasicCacheFactoryBean extends AbstractFactoryBeanS * Destroys the cache bean on Spring Container shutdown. * * @see org.springframework.beans.factory.DisposableBean#destroy() - * @see #destroyBeanFactoryLocator() * @see #close(GemFireCache) + * @see #fetchCache() * @see #isClose() */ @Override @@ -714,50 +575,13 @@ public abstract class AbstractBasicCacheFactoryBean extends AbstractFactoryBeanS 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; } - /** - * 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(); - } - /** * Configures the {@link GemFireCache} critical and eviction heap thresholds as percentages. * @@ -830,6 +654,29 @@ public abstract class AbstractBasicCacheFactoryBean extends AbstractFactoryBeanS return cache; } + /** + * 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(); + } + /** * Fetches an existing cache instance from the Apache Geode cache factory. * @@ -851,23 +698,6 @@ public abstract class AbstractBasicCacheFactoryBean extends AbstractFactoryBeanS 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}. @@ -888,33 +718,6 @@ public abstract class AbstractBasicCacheFactoryBean extends AbstractFactoryBeanS .orElse(factory); } - /** - * Loads the configured {@literal cache.xml} to initialize the {@link GemFireCache}. - * - * @param parameterized {@link Class} type extending {@link GemFireCache}. - * @param cache {@link GemFireCache} instance to initialize with {@literal cache.xml}; must not be {@literal null}. - * @return the given {@link GemFireCache}. - * @throws RuntimeException if the configured {@literal cache.xml} file could not be loaded - * into the {@link GemFireCache}. - * @see org.apache.geode.cache.GemFireCache#loadCacheXml(InputStream) - * @see org.apache.geode.cache.GemFireCache - */ - protected @NonNull T loadCacheXml(@NonNull 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; - } - /** * Registers configured, application-defined {@link TransactionListener TransactionListeners} with the cache * (transaction manager) to listen for and receive transaction events when a (cache) transaction is processed @@ -959,20 +762,6 @@ public abstract class AbstractBasicCacheFactoryBean extends AbstractFactoryBeanS return cache; } - /** - * Resolves the Apache Geode {@link Properties} used to configure the {@link GemFireCache}. - * - * @return the resolved Apache Geode {@link Properties} used to configure the {@link GemFireCache}. - * @see #setAndGetProperties(Properties) - * @see #getProperties() - * @see java.util.Properties - */ - protected @NonNull Properties resolveProperties() { - - return Optional.ofNullable(getProperties()) - .orElseGet(() -> setAndGetProperties(new Properties())); - } - /** * Translates the thrown Apache Geode {@link RuntimeException} into a corresponding {@link Exception} from Spring's * generic {@link DataAccessException} hierarchy if possible. diff --git a/spring-data-geode/src/main/java/org/springframework/data/gemfire/AbstractConfigurableCacheFactoryBean.java b/spring-data-geode/src/main/java/org/springframework/data/gemfire/AbstractConfigurableCacheFactoryBean.java new file mode 100644 index 00000000..47704412 --- /dev/null +++ b/spring-data-geode/src/main/java/org/springframework/data/gemfire/AbstractConfigurableCacheFactoryBean.java @@ -0,0 +1,296 @@ +/* + * 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.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.cache.Cache; +import org.apache.geode.cache.GemFireCache; +import org.apache.geode.cache.client.ClientCache; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.core.io.Resource; +import org.springframework.data.gemfire.support.GemfireBeanFactoryLocator; +import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; + +/** + * Abstract base class encapsulating functionality for (externally) configuring an Apache Geode {@link ClientCache} + * or peer {@link Cache} as a bean in the Spring context. + * + * @author John Blum + * @see java.io.File + * @see java.io.InputStream + * @see java.util.Properties + * @see org.apache.geode.cache.Cache + * @see org.apache.geode.cache.GemFireCache + * @see org.apache.geode.cache.client.ClientCache + * @see org.springframework.beans.factory.BeanFactory + * @see org.springframework.core.io.Resource + * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator + * @since 2.5.0 + */ +@SuppressWarnings("unused") +public abstract class AbstractConfigurableCacheFactoryBean extends AbstractBasicCacheFactoryBean { + + private boolean useBeanFactoryLocator = false; + + private GemfireBeanFactoryLocator beanFactoryLocator; + + 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; + } + + /** + * Returns an {@link Optional} reference to the configured {@link GemfireBeanFactoryLocator} used to + * resolve Spring bean references in Apache Geode native configuration metadata (e.g. {@literal cache.xml}). + * + * @return an {@link Optional} reference to the configured {@link GemfireBeanFactoryLocator}. + * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator + * @see #getBeanFactoryLocator() + * @see java.util.Optional + */ + public Optional getOptionalBeanFactoryLocator() { + return Optional.ofNullable(getBeanFactoryLocator()); + } + + /** + * 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; + } + + /** + * Returns an {@link Optional} reference to an Apache Geode native {@literal cache.xml} {@link Resource}. + * + * @return an {@link Optional} reference to an Apache Geode native {@literal cache.xml} {@link Resource}. + * @see org.springframework.core.io.Resource + * @see java.util.Optional + * @see #getCacheXml() + */ + public Optional getOptionalCacheXml() { + return Optional.ofNullable(getCacheXml()); + } + + /** + * Determines whether a {@literal cache.xml} {@link Resource} exists (i.e. is present). + * + * @return boolean value indicating whether a {@literal cache.xml} exists. + * @see org.springframework.core.io.Resource#exists() + * @see #getCacheXml() + */ + @SuppressWarnings("unused") + protected boolean isCacheXmlPresent() { + + Resource cacheXml = getCacheXml(); + + return cacheXml != null && cacheXml.exists(); + } + + /** + * Determines whether the optionally configured {@literal cache.xml} is resolvable as a {@link File} + * in the file system. + * + * @return a boolean value indicating whether the optionally configured {@literal cache.xml} + * is resolvable as a {@link File} in the file system. + * @see org.springframework.core.io.Resource#isFile() + * @see #getCacheXml() + * @see java.io.File + */ + protected boolean isCacheXmlResolvableAsAFile() { + + Resource cacheXml = getCacheXml(); + + return cacheXml != null && cacheXml.isFile(); + } + + /** + * 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 @Nullable 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; + } + + /** + * 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; + } + + /** + * 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; + } + + /** + * Initializes the {@link GemfireBeanFactoryLocator} if {@link #isUseBeanFactoryLocator()} returns {@literal true} + * and an existing {@link #getBeanFactoryLocator() GemfireBeanFactoryLocator} is not already present. + * + * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator#newBeanFactoryLocator(BeanFactory, String) + * @see #isUseBeanFactoryLocator() + * @see #getBeanFactoryLocator() + * @see #getBeanFactory() + * @see #getBeanName() + */ + @Override + public void afterPropertiesSet() throws Exception { + + super.afterPropertiesSet(); + + if (useBeanFactoryLocator()) { + setBeanFactoryLocator(GemfireBeanFactoryLocator.newBeanFactoryLocator(getBeanFactory(), getBeanName())); + } + } + + private boolean useBeanFactoryLocator() { + return isUseBeanFactoryLocator() && getBeanFactoryLocator() == null; + } + + /** + * Destroys and releases resources used by the {@link GemfireBeanFactoryLocator}, if present. + * + * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator#destroy() + */ + @Override + public void destroy() { + + super.destroy(); + + getOptionalBeanFactoryLocator().ifPresent(GemfireBeanFactoryLocator::destroy); + + setBeanFactoryLocator(null); + } + + /** + * Loads the configured {@literal cache.xml} to initialize the {@link GemFireCache}. + * + * @param parameterized {@link Class} type extending {@link GemFireCache}. + * @param cache {@link GemFireCache} instance to initialize with {@literal cache.xml}; must not be {@literal null}. + * @return the given {@link GemFireCache}. + * @throws RuntimeException if the configured {@literal cache.xml} file could not be loaded + * into the {@link GemFireCache}. + * @see org.apache.geode.cache.GemFireCache#loadCacheXml(InputStream) + * @see org.apache.geode.cache.GemFireCache + */ + protected @NonNull T loadCacheXml(@NonNull T cache) { + + // Load the cache.xml file (Resource) and initialize the cache + getOptionalCacheXml().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 GemFireCache}. + * + * @return the resolved Apache Geode {@link Properties} used to configure the {@link GemFireCache}. + * @see #setAndGetProperties(Properties) + * @see #getProperties() + * @see java.util.Properties + */ + protected @NonNull Properties resolveProperties() { + + Properties properties = getProperties(); + + return properties != null ? properties : setAndGetProperties(new Properties()); + } +} diff --git a/spring-data-geode/src/main/java/org/springframework/data/gemfire/AbstractResolvableCacheFactoryBean.java b/spring-data-geode/src/main/java/org/springframework/data/gemfire/AbstractResolvableCacheFactoryBean.java index 2f4b24af..8c24b7b9 100644 --- a/spring-data-geode/src/main/java/org/springframework/data/gemfire/AbstractResolvableCacheFactoryBean.java +++ b/spring-data-geode/src/main/java/org/springframework/data/gemfire/AbstractResolvableCacheFactoryBean.java @@ -36,10 +36,10 @@ import org.springframework.lang.NonNull; * @see org.apache.geode.cache.GemFireCache * @see org.apache.geode.distributed.DistributedMember * @see org.apache.geode.distributed.DistributedSystem - * @see org.springframework.data.gemfire.AbstractBasicCacheFactoryBean + * @see org.springframework.data.gemfire.AbstractConfigurableCacheFactoryBean * @since 2.5.0 */ -public abstract class AbstractResolvableCacheFactoryBean extends AbstractBasicCacheFactoryBean { +public abstract class AbstractResolvableCacheFactoryBean extends AbstractConfigurableCacheFactoryBean { private volatile String cacheResolutionMessagePrefix; diff --git a/spring-data-geode/src/test/java/org/springframework/data/gemfire/CacheFactoryBeanUnitTests.java b/spring-data-geode/src/test/java/org/springframework/data/gemfire/CacheFactoryBeanUnitTests.java index 1c290375..8115c040 100644 --- a/spring-data-geode/src/test/java/org/springframework/data/gemfire/CacheFactoryBeanUnitTests.java +++ b/spring-data-geode/src/test/java/org/springframework/data/gemfire/CacheFactoryBeanUnitTests.java @@ -98,6 +98,7 @@ public class CacheFactoryBeanUnitTests { CacheFactoryBean cacheFactoryBean = spy(new CacheFactoryBean()); + cacheFactoryBean.setUseBeanFactoryLocator(true); cacheFactoryBean.afterPropertiesSet(); InOrder orderVerifier = inOrder(cacheFactoryBean); @@ -106,7 +107,7 @@ public class CacheFactoryBeanUnitTests { 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(); + orderVerifier.verify(cacheFactoryBean, times(1)).setBeanFactoryLocator(isA(GemfireBeanFactoryLocator.class)); } @Test @@ -738,7 +739,6 @@ public class CacheFactoryBeanUnitTests { 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(); @@ -761,7 +761,6 @@ public class CacheFactoryBeanUnitTests { verify(cacheFactoryBean, times(1)).isClose(); verify(cacheFactoryBean, times(1)).fetchCache(); verify(cacheFactoryBean, times(1)).close(isNull()); - verify(cacheFactoryBean, times(1)).destroyBeanFactoryLocator(); } @Test @@ -776,7 +775,6 @@ public class CacheFactoryBeanUnitTests { verify(cacheFactoryBean, times(1)).isClose(); verify(cacheFactoryBean, never()).fetchCache(); verify(cacheFactoryBean, never()).close(any()); - verify(cacheFactoryBean, never()).destroyBeanFactoryLocator(); } @Test