/* * Copyright 2010-2013 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 * * http://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.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.geode.cache.GemFireCache; import org.apache.geode.cache.Region; import org.springframework.beans.factory.BeanInitializationException; import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.util.Assert; import org.springframework.util.StringUtils; /** * Spring {@link FactoryBean} for looking up generic GemFire {@link Region Regions}. If lookups are not enabled * or the {@link Region} does not exist, an Exception is thrown. * * @author Costin Leau * @author John Blum * @see org.springframework.beans.factory.BeanNameAware * @see org.springframework.beans.factory.FactoryBean * @see org.springframework.beans.factory.InitializingBean * @see org.apache.geode.cache.Region */ @SuppressWarnings("unused") public abstract class RegionLookupFactoryBean<K, V> implements FactoryBean<Region<K, V>>, InitializingBean, BeanNameAware { protected final Log log = LogFactory.getLog(getClass()); private Boolean lookupEnabled = false; private GemFireCache cache; private Region<?, ?> parent; private volatile Region<K, V> region; private String beanName; private String name; private String regionName; /** * @inheritDoc */ @Override @SuppressWarnings("all") public void afterPropertiesSet() throws Exception { Assert.notNull(this.cache, "A 'Cache' reference must be set"); String regionName = resolveRegionName(); Assert.hasText(regionName, "'regionName', 'name' or 'beanName' property must be set"); synchronized (this.cache) { if (isLookupEnabled()) { this.region = Optional.ofNullable(getParent()) .map(parentRegion -> parentRegion.<K, V>getSubregion(regionName)) .orElseGet(() -> this.cache.<K, V>getRegion(regionName)); } if (region != null) { log.info(String.format("Found Region [%1$s] in Cache [%2$s]", regionName, cache.getName())); } else { log.info(String.format("Falling back to creating Region [%1$s] in Cache [%2$s]", regionName, cache.getName())); region = lookupRegion(cache, regionName); } } } /** * Method to perform a lookup when the named {@link Region} does not exist. By default, this implementation * throws an exception. * * @param cache reference to the GemFire cache. * @param regionName name of the GemFire {@link Region}. * @return the {@link Region} in the GemFire cache with the given name. * @throws BeanInitializationException if the lookup operation fails. * @see org.apache.geode.cache.Region */ protected Region<K, V> lookupRegion(GemFireCache cache, String regionName) throws Exception { throw new BeanInitializationException(String.format( "Region [%1$s] in Cache [%2$s] not found", regionName, cache)); } /** * @inheritDoc */ @Override public Region<K, V> getObject() throws Exception { return getRegion(); } /** * @inheritDoc */ @Override public Class<?> getObjectType() { Region region = getRegion(); return (region != null ? region.getClass() : Region.class); } /** * @inheritDoc */ @Override public boolean isSingleton() { return true; } /** * Resolves the name of the GemFire {@link Region}. * * @return a {@link String} indicating the name of the GemFire {@link Region}. * @see org.apache.geode.cache.Region#getName() */ public String resolveRegionName() { return (StringUtils.hasText(this.regionName) ? this.regionName : (StringUtils.hasText(this.name) ? this.name : this.beanName)); } /** * Sets the name of the {@link Region} based on the bean 'id' attribute. If no {@link Region} is found * with the given name, a new one will be created. * * @param name name of this {@link Region} bean in the Spring {@link org.springframework.context.ApplicationContext}. * @see org.springframework.beans.factory.BeanNameAware#setBeanName(String) */ public void setBeanName(String name) { this.beanName = name; } /** * Sets a reference to the {@link GemFireCache} used to create the {@link Region}. * * @param cache reference to the {@link GemFireCache}. * @see org.springframework.data.gemfire.CacheFactoryBean * @see org.apache.geode.cache.GemFireCache */ public void setCache(GemFireCache cache) { this.cache = cache; } /* (non-Javadoc) */ boolean isLookupEnabled() { return Boolean.TRUE.equals(getLookupEnabled()); } /* (non-Javadoc) */ public void setLookupEnabled(Boolean lookupEnabled) { this.lookupEnabled = lookupEnabled; } /* (non-Javadoc) */ public Boolean getLookupEnabled() { return lookupEnabled; } /** * Sets the name of the cache {@link Region} based on the bean 'name' attribute. If no {@link Region} is found * with the given name, a new one will be created. If no name is given, the value of the 'beanName' property * will be used. * * @param name {@link Region} name. * @see #setBeanName(String) */ public void setName(String name) { this.name = name; } /** * Sets a reference to the parent {@link Region} to indicated this {@link FactoryBean} represents a GemFire cache * {@link Region Sub-Region}. * * @param parent reference to the parent {@link Region}. * @see org.apache.geode.cache.Region */ public void setParent(Region<?, ?> parent) { this.parent = parent; } /** * Returns a reference to the parent {@link Region} indicating this {@link FactoryBean} represents a GemFire cache * {@link Region Sub-Region}. * * @return a reference to the parent {@link Region} or {@literal null} if this {@link Region} * is not a {@link Region Sub-Region}. * @see org.apache.geode.cache.Region */ protected Region<?, ?> getParent() { return this.parent; } /** * Returns a reference to the GemFire {@link Region} resolved by this Spring {@link FactoryBean} * during the lookup operation; maybe a new {@link Region}. * * @return a reference to the GemFire {@link Region} resolved during lookup. * @see org.apache.geode.cache.Region */ protected Region<K, V> getRegion() { return this.region; } /** * Sets the name of the cache {@link Region}. If no {@link Region} is found with the given name, * a new one will be created. If no name is given, the value of the 'name' property will be used. * * @param regionName name of the {@link Region}. * @see #setName(String) */ public void setRegionName(String regionName) { this.regionName = regionName; } }