Java tutorial
/* * Copyright 2010-2019 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 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 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.DynamicRegionFactory; 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.SpringUtils; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; /** * Spring {@link FactoryBean} used to construct, configure and initialize a Pivotal GemFire/Apache Geode * {@link Cache peer cache). * * Allows either retrieval of an existing, open {@link Cache} or 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 * @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.DynamicRegionFactory * @see org.apache.geode.cache.RegionService * @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<GemFireCache> implements DisposableBean, InitializingBean, PersistenceExceptionTranslator, Phased { 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 DynamicRegionSupport dynamicRegionSupport; 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<PeerCacheConfigurer> peerCacheConfigurers = new ArrayList<>(); private List<JndiDataSource> jndiDataSources; private List<TransactionListener> transactionListeners; private PdxSerializer pdxSerializer; private 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}. * * @see #getCompositePeerCacheConfigurer() * @see #applyPeerCacheConfigurers(PeerCacheConfigurer...) */ protected void applyCacheConfigurers() { PeerCacheConfigurer autoReconnectClusterConfigurationConfigurer = (beanName, cacheFactoryBean) -> { Properties gemfireProperties = resolveProperties(); gemfireProperties.setProperty("disable-auto-reconnect", String.valueOf(!Boolean.TRUE.equals(getEnableAutoReconnect()))); gemfireProperties.setProperty("use-cluster-configuration", String.valueOf(Boolean.TRUE.equals(getUseClusterConfiguration()))); }; this.peerCacheConfigurers.add(autoReconnectClusterConfigurationConfigurer); applyPeerCacheConfigurers(getCompositePeerCacheConfigurer()); } /** * Applies the given array of {@link PeerCacheConfigurer PeerCacheConfigurers} 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))); } /** * Applies the given {@link Iterable} of {@link PeerCacheConfigurer PeerCacheConfigurers} * to this {@link CacheFactoryBean}. * * @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<PeerCacheConfigurer> peerCacheConfigurers) { stream(nullSafeIterable(peerCacheConfigurers).spliterator(), false) .forEach(clientCacheConfigurer -> clientCacheConfigurer.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() */ void initBeanFactoryLocator() { if (isUseBeanFactoryLocator() && this.beanFactoryLocator == null) { this.beanFactoryLocator = newBeanFactoryLocator(getBeanFactory(), getBeanName()); } } /** * Initializes the {@link Cache}. * * @return a reference to the initialized {@link Cache}. * @see org.apache.geode.cache.Cache * @see #resolveCache() * @see #postProcess(GemFireCache) * @see #setCache(GemFireCache) */ @SuppressWarnings("deprecation") GemFireCache init() { ClassLoader currentThreadContextClassLoader = Thread.currentThread().getContextClassLoader(); try { // Use Spring Bean ClassLoader to load Spring configured, Pivotal GemFire/Apache Geode classes Thread.currentThread().setContextClassLoader(getBeanClassLoader()); setCache(postProcess(resolveCache())); Optional.<GemFireCache>ofNullable(getCache()).ifPresent(cache -> { Optional.ofNullable(cache.getDistributedSystem()).map(DistributedSystem::getDistributedMember) .ifPresent(member -> logInfo(() -> String.format( "Connected to Distributed System [%1$s] as Member [%2$s]".concat( " in Group(s) [%3$s] with Role(s) [%4$s] on Host [%5$s] having PID [%6$d]"), cache.getDistributedSystem().getName(), member.getId(), member.getGroups(), member.getRoles(), member.getHost(), member.getProcessId()))); logInfo(() -> String.format("%1$s %2$s version [%3$s] Cache [%4$s]", this.cacheResolutionMessagePrefix, apacheGeodeProductName(), apacheGeodeVersion(), cache.getName())); }); return getCache(); } catch (Exception cause) { throw newRuntimeException(cause, "Error occurred when initializing peer cache"); } finally { Thread.currentThread().setContextClassLoader(currentThreadContextClassLoader); } } /** * Resolves the {@link Cache} by first attempting to lookup an existing {@link Cache} instance in the JVM. * If an existing {@link Cache} could not be found, then this method proceeds in attempting to create * a new {@link Cache} instance. * * @param <T> parameterized {@link Class} type extension of {@link GemFireCache}. * @return the resolved {@link Cache} instance. * @see org.apache.geode.cache.Cache * @see #fetchCache() * @see #resolveProperties() * @see #createFactory(java.util.Properties) * @see #configureFactory(Object) * @see #createCache(Object) */ @SuppressWarnings("unchecked") protected <T extends GemFireCache> T resolveCache() { try { this.cacheResolutionMessagePrefix = "Found existing"; return (T) fetchCache(); } catch (CacheClosedException cause) { this.cacheResolutionMessagePrefix = "Created new"; initDynamicRegionFactory(); return (T) createCache( postProcess(configureFactory(initializeFactory(createFactory(resolveProperties()))))); } } /** * Fetches an existing {@link Cache} instance from the {@link CacheFactory}. * * @param <T> 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() */ @SuppressWarnings("unchecked") protected <T extends GemFireCache> T fetchCache() { return (T) Optional.ofNullable(getCache()).orElseGet(CacheFactory::getAnyInstance); } /** * If Pivotal GemFire/Apache Geode Dynamic Regions are enabled, create and initialize a {@link DynamicRegionFactory} * before creating the {@link Cache}. * * @see org.springframework.data.gemfire.CacheFactoryBean.DynamicRegionSupport#initDynamicRegionFactory() * @see #getDynamicRegionSupport() */ private void initDynamicRegionFactory() { Optional.ofNullable(getDynamicRegionSupport()) .ifPresent(DynamicRegionSupport::initializeDynamicRegionFactory); } /** * Resolves the Pivotal GemFire/Apache Geode {@link Properties} used to configure the {@link Cache}. * * @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}. * @see org.apache.geode.cache.CacheFactory * @see java.util.Properties */ protected Object createFactory(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 org.apache.geode.cache.CacheFactory * @see #configurePdx(CacheFactory) */ protected Object configureFactory(Object factory) { return configureSecurity(configurePdx((CacheFactory) factory)); } /** * Configures PDX for this peer {@link Cache} instance. * * @param cacheFactory {@link CacheFactory} used to configure the peer {@link Cache} with PDX. * @return the given {@link CacheFactory}. * @see org.apache.geode.cache.CacheFactory */ 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; } /** * Configures security for this peer {@link Cache} instance. * * @param cacheFactory {@link CacheFactory} used to configure the peer {@link Cache} with security. * @return the given {@link CacheFactory}. * @see org.apache.geode.cache.CacheFactory */ private CacheFactory configureSecurity(CacheFactory cacheFactory) { Optional.ofNullable(getSecurityManager()).ifPresent(cacheFactory::setSecurityManager); return cacheFactory; } /** * Post processes 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) { return factory; } /** * Creates a new {@link Cache} instance using the provided {@link Object factory}. * * @param <T> {@link Class sub-type} of {@link GemFireCache}. * @param factory instance of {@link CacheFactory}. * @return a new instance of {@link Cache} created by the provided {@link Object factory}. * @see org.apache.geode.cache.CacheFactory#create() * @see org.apache.geode.cache.GemFireCache */ @SuppressWarnings("unchecked") protected <T extends GemFireCache> T createCache(Object factory) { return (T) ((CacheFactory) factory).create(); } /** * Post processes the {@link GemFireCache} by loading any {@literal cache.xml}, applying custom settings * specified in SDG XML configuration meta-data, and registering appropriate Transaction Listeners, Writer * and JNDI settings. * * @param <T> Parameterized {@link Class} type extension of {@link GemFireCache}. * @param cache {@link GemFireCache} instance to post process. * @return the given {@link GemFireCache}. * @see org.apache.geode.cache.Cache#loadCacheXml(java.io.InputStream) * @see #getCacheXml() * @see #configureHeapPercentages(org.apache.geode.cache.GemFireCache) * @see #registerJndiDataSources() * @see #registerTransactionListeners(org.apache.geode.cache.GemFireCache) * @see #registerTransactionWriter(org.apache.geode.cache.GemFireCache) */ @SuppressWarnings("all") protected <T extends GemFireCache> T postProcess(T cache) { loadCacheXml(cache); Optional.ofNullable(getCopyOnRead()).ifPresent(cache::setCopyOnRead); if (cache instanceof Cache) { Optional.ofNullable(getGatewayConflictResolver()) .ifPresent(((Cache) cache)::setGatewayConflictResolver); Optional.ofNullable(getLockLease()).ifPresent(((Cache) cache)::setLockLease); Optional.ofNullable(getLockTimeout()).ifPresent(((Cache) cache)::setLockTimeout); Optional.ofNullable(getMessageSyncInterval()).ifPresent(((Cache) cache)::setMessageSyncInterval); Optional.ofNullable(getSearchTimeout()).ifPresent(((Cache) cache)::setSearchTimeout); } configureHeapPercentages(cache); configureOffHeapPercentages(cache); registerJndiDataSources(cache); registerTransactionListeners(cache); registerTransactionWriter(cache); return cache; } private <T extends GemFireCache> 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 -> { String type = jndiDataSource.getAttributes().get("type"); JndiDataSourceType jndiDataSourceType = JndiDataSourceType.valueOfIgnoreCase(type); Assert.notNull(jndiDataSourceType, String.format("'jndi-binding' 'type' [%1$s] is invalid; 'type' must be one of %2$s", type, Arrays.toString(JndiDataSourceType.values()))); jndiDataSource.getAttributes().put("type", jndiDataSourceType.getName()); SpringUtils.safeRunOperation( () -> JNDIInvoker.mapDatasource(jndiDataSource.getAttributes(), jndiDataSource.getProps())); }); return cache; } private GemFireCache registerTransactionListeners(GemFireCache cache) { nullSafeCollection(getTransactionListeners()).forEach( transactionListener -> cache.getCacheTransactionManager().addListener(transactionListener)); return cache; } private GemFireCache registerTransactionWriter(GemFireCache cache) { Optional.ofNullable(getTransactionWriter()) .ifPresent(it -> cache.getCacheTransactionManager().setWriter(it)); 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. * * @throws Exception if an error occurs while closing the cache. * @see org.springframework.beans.factory.DisposableBean#destroy() * @see #destroyBeanFactoryLocator() * @see #close(GemFireCache) * @see #isClose() */ @Override public void destroy() throws Exception { 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 @SuppressWarnings("all") 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 extends GemFireCache> 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() */ @SuppressWarnings("all") private boolean isCacheXmlAvailable() { try { return getCacheXmlFile() != null; } catch (Throwable ignore) { return false; } } /** * 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 @SuppressWarnings("all") public GemFireCache getObject() throws Exception { return Optional.<GemFireCache>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 @SuppressWarnings("unchecked") public Class<? extends GemFireCache> getObjectType() { return Optional.ofNullable(this.<Cache>getCache()).<Class>map(Object::getClass).orElse(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 */ 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 */ 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. * * @return the Composite {@link PeerCacheConfigurer}. * @see org.springframework.data.gemfire.config.annotation.PeerCacheConfigurer */ public PeerCacheConfigurer getCompositePeerCacheConfigurer() { 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 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 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; } /** * Sets an instance of the DynamicRegionSupport to support Dynamic Regions in this Pivotal GemFire Cache. * * @param dynamicRegionSupport the DynamicRegionSupport class to setup Dynamic Regions in this Cache. */ public void setDynamicRegionSupport(DynamicRegionSupport dynamicRegionSupport) { this.dynamicRegionSupport = dynamicRegionSupport; } /** * @return the dynamicRegionSupport */ public DynamicRegionSupport getDynamicRegionSupport() { return dynamicRegionSupport; } /** * Controls whether auto-reconnect functionality introduced in Pivotal GemFire 8 is enabled or not. * * @param enableAutoReconnect a boolean value to enable/disable auto-reconnect functionality. * @since Pivotal GemFire 8.0 */ public void setEnableAutoReconnect(Boolean enableAutoReconnect) { this.enableAutoReconnect = enableAutoReconnect; } /** * Gets the value for the auto-reconnect setting. * * @return a boolean value indicating whether auto-reconnect was specified (non-null) and whether it was enabled * or not. */ public Boolean getEnableAutoReconnect() { 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 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 Pivotal GemFire 7.0 or higher * @param gatewayConflictResolver defined as Object in the signature for backward * compatibility with Gemfire 6 compatibility. This must be an instance of * {@link org.apache.geode.cache.util.GatewayConflictResolver} */ public void setGatewayConflictResolver(GatewayConflictResolver gatewayConflictResolver) { this.gatewayConflictResolver = gatewayConflictResolver; } /** * @return the gatewayConflictResolver */ public GatewayConflictResolver getGatewayConflictResolver() { return gatewayConflictResolver; } /** * @param jndiDataSources the list of configured JndiDataSources to use with this Cache. */ public void setJndiDataSources(List<JndiDataSource> jndiDataSources) { this.jndiDataSources = jndiDataSources; } /** * @return the list of configured JndiDataSources. */ public List<JndiDataSource> getJndiDataSources() { return jndiDataSources; } /** * Sets the number of seconds for implicit and explicit object lock leases to timeout. * * @param lockLease an integer value indicating the object lock lease timeout. */ public void setLockLease(Integer lockLease) { this.lockLease = lockLease; } /** * @return the lockLease */ public Integer getLockLease() { return lockLease; } /** * Sets the number of seconds in which the implicit object lock request will timeout. * * @param lockTimeout an integer value specifying the object lock request timeout. */ public void setLockTimeout(Integer lockTimeout) { this.lockTimeout = lockTimeout; } /** * @return the lockTimeout */ public Integer getLockTimeout() { return lockTimeout; } /** * Set for client subscription queue synchronization when this member acts as a server to clients * and server redundancy is used. Sets the frequency (in seconds) at which the primary server sends messages * to its secondary servers to remove queued events that have already been processed by the clients. * * @param messageSyncInterval an integer value specifying the number of seconds in which the primary server * sends messages to secondary servers. */ public void setMessageSyncInterval(Integer messageSyncInterval) { this.messageSyncInterval = messageSyncInterval; } /** * @return the messageSyncInterval */ public Integer getMessageSyncInterval() { return 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 pdxDiskStoreName; } /** * Controls whether pdx ignores fields that were unread during * deserialization. Applicable on Pivotal 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 pdxIgnoreUnreadFields; } /** * Controls whether type metadata for PDX objects is persisted to disk. Applicable on Pivotal 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 pdxPersistent; } /** * Sets the object preference to PdxInstance. Applicable on Pivotal 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 pdxReadSerialized; } /** * Sets the {@link PdxSerializable} for this cache. Applicable on GemFire * 6.6 or higher. The argument is of type object for compatibility with * Pivotal 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 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. * * @param peerCacheConfigurers array of {@link PeerCacheConfigurer PeerCacheConfigurers} used to apply * additional configuration to this {@link CacheFactoryBean}. * @see org.springframework.data.gemfire.config.annotation.PeerCacheConfigurer * @see #setPeerCacheConfigurers(List) */ public void setPeerCacheConfigurers(PeerCacheConfigurer... peerCacheConfigurers) { setPeerCacheConfigurers(Arrays.asList(nullSafeArray(peerCacheConfigurers, PeerCacheConfigurer.class))); } /** * Null-safe operation to set an {@link Iterable} of {@link PeerCacheConfigurer PeerCacheConfigurers} to apply * additional configuration to this {@link CacheFactoryBean} when using Annotation-based configuration. * * @param peerCacheConfigurers {@link Iterable} of {@link PeerCacheConfigurer PeerCacheConfigurers} used to apply * additional configuration to this {@link CacheFactoryBean}. * @see org.springframework.data.gemfire.config.annotation.PeerCacheConfigurer */ public void setPeerCacheConfigurers(List<PeerCacheConfigurer> peerCacheConfigurers) { Optional.ofNullable(peerCacheConfigurers).ifPresent(this.peerCacheConfigurers::addAll); } /** * Set the number of seconds a netSearch operation can wait for data before timing out. * * @param searchTimeout an integer value indicating the netSearch timeout value. */ public void setSearchTimeout(Integer searchTimeout) { this.searchTimeout = searchTimeout; } /** * @return the searchTimeout */ public Integer getSearchTimeout() { return searchTimeout; } /** * Configures the {@link org.apache.geode.security.SecurityManager} used to secure this cache. * * @param securityManager {@link org.apache.geode.security.SecurityManager} used to secure this cache. * @see org.apache.geode.security.SecurityManager */ public void setSecurityManager(SecurityManager securityManager) { this.securityManager = securityManager; } /** * Returns the {@link org.apache.geode.security.SecurityManager} used to secure this cache. * * @return the {@link org.apache.geode.security.SecurityManager} used to secure this cache. * @see org.apache.geode.security.SecurityManager */ public SecurityManager getSecurityManager() { return securityManager; } /** * Sets the list of TransactionListeners used to configure the Cache to receive transaction events after * the transaction is processed (committed, rolled back). * * @param transactionListeners the list of Pivotal GemFire TransactionListeners listening for transaction events. * @see org.apache.geode.cache.TransactionListener */ public void setTransactionListeners(List<TransactionListener> transactionListeners) { this.transactionListeners = transactionListeners; } /** * @return the transactionListeners */ public List<TransactionListener> getTransactionListeners() { return transactionListeners; } /** * Sets the TransactionWriter used to configure the Cache for handling transaction events, such as to veto * the transaction or update an external DB before the commit. * * @param transactionWriter the Pivotal GemFire TransactionWriter callback receiving transaction events. * @see org.apache.geode.cache.TransactionWriter */ public void setTransactionWriter(TransactionWriter transactionWriter) { this.transactionWriter = transactionWriter; } /** * @return the transactionWriter */ public TransactionWriter getTransactionWriter() { return 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. * * @param useSharedConfiguration boolean value to set the {@literal use-shared-configuration} * Pivotal GemFire/Apache Geode distribution configuration setting. */ public void setUseClusterConfiguration(Boolean useSharedConfiguration) { this.useClusterConfiguration = useSharedConfiguration; } /** * Return the state of the {@literal use-shared-configuration} Pivotal GemFire/Apache Geode * distribution configuration setting. * * @return the current boolean value for the {@literal use-shared-configuration} * Pivotal GemFire/Apache Geode distribution configuration setting. */ public Boolean getUseClusterConfiguration() { 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<T> { /** * 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 class DynamicRegionSupport { private Boolean persistent = Boolean.TRUE; private Boolean registerInterest = Boolean.TRUE; private String diskDirectory; private String poolName; public void setDiskDir(String diskDirectory) { this.diskDirectory = diskDirectory; } public String getDiskDir() { return diskDirectory; } public void setPersistent(Boolean persistent) { this.persistent = persistent; } public Boolean getPersistent() { return persistent; } public void setPoolName(String poolName) { this.poolName = poolName; } public String getPoolName() { return poolName; } public void setRegisterInterest(Boolean registerInterest) { this.registerInterest = registerInterest; } public Boolean getRegisterInterest() { return registerInterest; } public void initializeDynamicRegionFactory() { File localDiskDirectory = this.diskDirectory != null ? new File(this.diskDirectory) : null; DynamicRegionFactory.Config config = new DynamicRegionFactory.Config(localDiskDirectory, this.poolName, this.persistent, this.registerInterest); DynamicRegionFactory.get().open(config); } } public static class JndiDataSource { private List<ConfigProperty> configProperties; private Map<String, String> attributes; public Map<String, String> getAttributes() { return this.attributes; } public void setAttributes(Map<String, String> attributes) { this.attributes = attributes; } public List<ConfigProperty> getProps() { return this.configProperties; } public void setProps(List<ConfigProperty> props) { this.configProperties = props; } } }