SGF-863 - Add support in the XML Namespace for Region to AsyncEventQueue and GatewaySender associations by ID.
This commit is contained in:
@@ -13,13 +13,15 @@
|
||||
* 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.ArrayUtils.nullSafeArray;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.geode.cache.CacheListener;
|
||||
import org.apache.geode.cache.CacheLoader;
|
||||
@@ -29,7 +31,9 @@ import org.apache.geode.cache.ExpirationAttributes;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.asyncqueue.AsyncEventQueue;
|
||||
import org.apache.geode.cache.wan.GatewaySender;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* The LookupRegionFactoryBean class is a concrete implementation of ResolvableRegionFactoryBean for handling
|
||||
@@ -66,6 +70,9 @@ public class LookupRegionFactoryBean<K, V> extends ResolvableRegionFactoryBean<K
|
||||
|
||||
private Integer evictionMaximum;
|
||||
|
||||
private String[] asyncEventQueueIds;
|
||||
private String[] gatewaySenderIds;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
|
||||
@@ -73,10 +80,10 @@ public class LookupRegionFactoryBean<K, V> extends ResolvableRegionFactoryBean<K
|
||||
|
||||
Optional.ofNullable(getRegion().getAttributesMutator()).ifPresent(attributesMutator -> {
|
||||
|
||||
Arrays.stream(nullSafeArray(this.asyncEventQueues, AsyncEventQueue.class))
|
||||
.map(AsyncEventQueue::getId)
|
||||
.forEach(attributesMutator::addAsyncEventQueueId);
|
||||
// AsyncEventQueues (AEQ)
|
||||
getConfiguredAsyncEventQueueIds().forEach(attributesMutator::addAsyncEventQueueId);
|
||||
|
||||
// CacheListeners
|
||||
Arrays.stream(nullSafeArray(this.cacheListeners, CacheListener.class))
|
||||
.forEach(attributesMutator::addCacheListener);
|
||||
|
||||
@@ -102,12 +109,43 @@ public class LookupRegionFactoryBean<K, V> extends ResolvableRegionFactoryBean<K
|
||||
Optional.ofNullable(this.regionTimeToLive).ifPresent(attributesMutator::setRegionTimeToLive);
|
||||
}
|
||||
|
||||
Arrays.stream(nullSafeArray(this.gatewaySenders, GatewaySender.class))
|
||||
.map(GatewaySender::getId)
|
||||
.forEach(attributesMutator::addGatewaySenderId);
|
||||
// GatewaySenders
|
||||
getConfiguredGatewaySenderIds().forEach(attributesMutator::addGatewaySenderId);
|
||||
});
|
||||
}
|
||||
|
||||
private Set<String> getConfiguredAsyncEventQueueIds() {
|
||||
|
||||
Set<String> asyncEventQueueIds = new HashSet<>();
|
||||
|
||||
Arrays.stream(nullSafeArray(this.asyncEventQueues, AsyncEventQueue.class))
|
||||
.map(AsyncEventQueue::getId)
|
||||
.collect(Collectors.toCollection(() -> asyncEventQueueIds));
|
||||
|
||||
Arrays.stream(nullSafeArray(this.asyncEventQueueIds, String.class))
|
||||
.filter(StringUtils::hasText)
|
||||
.map(String::trim)
|
||||
.collect(Collectors.toCollection(() -> asyncEventQueueIds));
|
||||
|
||||
return asyncEventQueueIds;
|
||||
}
|
||||
|
||||
private Set<String> getConfiguredGatewaySenderIds() {
|
||||
|
||||
Set<String> gatewaySenderIds = new HashSet<>();
|
||||
|
||||
Arrays.stream(nullSafeArray(this.gatewaySenders, GatewaySender.class))
|
||||
.map(GatewaySender::getId)
|
||||
.collect(Collectors.toCollection(() -> gatewaySenderIds));
|
||||
|
||||
Arrays.stream(nullSafeArray(this.gatewaySenderIds, String.class))
|
||||
.filter(StringUtils::hasText)
|
||||
.map(String::trim)
|
||||
.collect(Collectors.toCollection(() -> gatewaySenderIds));
|
||||
|
||||
return gatewaySenderIds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isLookupEnabled() {
|
||||
return true;
|
||||
@@ -117,6 +155,10 @@ public class LookupRegionFactoryBean<K, V> extends ResolvableRegionFactoryBean<K
|
||||
this.asyncEventQueues = asyncEventQueues;
|
||||
}
|
||||
|
||||
public void setAsyncEventQueueIds(String[] asyncEventQueueIds) {
|
||||
this.asyncEventQueueIds = asyncEventQueueIds;
|
||||
}
|
||||
|
||||
public void setCacheListeners(CacheListener<K, V>[] cacheListeners) {
|
||||
this.cacheListeners = cacheListeners;
|
||||
}
|
||||
@@ -161,6 +203,10 @@ public class LookupRegionFactoryBean<K, V> extends ResolvableRegionFactoryBean<K
|
||||
this.gatewaySenders = gatewaySenders;
|
||||
}
|
||||
|
||||
public void setGatewaySenderIds(String[] gatewaySenderIds) {
|
||||
this.gatewaySenderIds = gatewaySenderIds;
|
||||
}
|
||||
|
||||
public void setRegionIdleTimeout(ExpirationAttributes regionIdleTimeout) {
|
||||
setStatisticsEnabled(regionIdleTimeout != null);
|
||||
this.regionIdleTimeout = regionIdleTimeout;
|
||||
|
||||
@@ -18,9 +18,12 @@ package org.springframework.data.gemfire;
|
||||
import static java.util.Arrays.stream;
|
||||
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
|
||||
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException;
|
||||
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.geode.cache.AttributesFactory;
|
||||
import org.apache.geode.cache.Cache;
|
||||
@@ -138,6 +141,9 @@ public abstract class PeerRegionFactoryBean<K, V> extends ConfigurableRegionFact
|
||||
|
||||
private String diskStoreName;
|
||||
|
||||
private String[] asyncEventQueueIds;
|
||||
private String[] gatewaySenderIds;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Region} with the given {@link String name}.
|
||||
*
|
||||
@@ -252,8 +258,7 @@ public abstract class PeerRegionFactoryBean<K, V> extends ConfigurableRegionFact
|
||||
|
||||
regionFactory.setStatisticsEnabled(resolveStatisticsEnabled());
|
||||
|
||||
stream(nullSafeArray(this.asyncEventQueues, AsyncEventQueue.class))
|
||||
.forEach(asyncEventQueue -> regionFactory.addAsyncEventQueueId(asyncEventQueue.getId()));
|
||||
getConfiguredAsyncEventQueueIds().forEach(regionFactory::addAsyncEventQueueId);
|
||||
|
||||
stream(nullSafeArray(this.cacheListeners, CacheListener.class)).forEach(regionFactory::addCacheListener);
|
||||
|
||||
@@ -279,8 +284,7 @@ public abstract class PeerRegionFactoryBean<K, V> extends ConfigurableRegionFact
|
||||
|
||||
Optional.ofNullable(this.evictionAttributes).ifPresent(regionFactory::setEvictionAttributes);
|
||||
|
||||
stream(nullSafeArray(this.gatewaySenders, GatewaySender.class))
|
||||
.forEach(gatewaySender -> regionFactory.addGatewaySenderId(gatewaySender.getId()));
|
||||
getConfiguredGatewaySenderIds().forEach(regionFactory::addGatewaySenderId);
|
||||
|
||||
Optional.ofNullable(this.keyConstraint).ifPresent(regionFactory::setKeyConstraint);
|
||||
|
||||
@@ -312,6 +316,38 @@ public abstract class PeerRegionFactoryBean<K, V> extends ConfigurableRegionFact
|
||||
return regionFactory;
|
||||
}
|
||||
|
||||
private Set<String> getConfiguredAsyncEventQueueIds() {
|
||||
|
||||
Set<String> asyncEventQueueIds = new HashSet<>();
|
||||
|
||||
Arrays.stream(nullSafeArray(this.asyncEventQueues, AsyncEventQueue.class))
|
||||
.map(AsyncEventQueue::getId)
|
||||
.collect(Collectors.toCollection(() -> asyncEventQueueIds));
|
||||
|
||||
Arrays.stream(nullSafeArray(this.asyncEventQueueIds, String.class))
|
||||
.filter(StringUtils::hasText)
|
||||
.map(String::trim)
|
||||
.collect(Collectors.toCollection(() -> asyncEventQueueIds));
|
||||
|
||||
return asyncEventQueueIds;
|
||||
}
|
||||
|
||||
private Set<String> getConfiguredGatewaySenderIds() {
|
||||
|
||||
Set<String> gatewaySenderIds = new HashSet<>();
|
||||
|
||||
Arrays.stream(nullSafeArray(this.gatewaySenders, GatewaySender.class))
|
||||
.map(GatewaySender::getId)
|
||||
.collect(Collectors.toCollection(() -> gatewaySenderIds));
|
||||
|
||||
Arrays.stream(nullSafeArray(this.gatewaySenderIds, String.class))
|
||||
.filter(StringUtils::hasText)
|
||||
.map(String::trim)
|
||||
.collect(Collectors.toCollection(() -> gatewaySenderIds));
|
||||
|
||||
return gatewaySenderIds;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
@@ -627,6 +663,10 @@ public abstract class PeerRegionFactoryBean<K, V> extends ConfigurableRegionFact
|
||||
this.asyncEventQueues = asyncEventQueues;
|
||||
}
|
||||
|
||||
public void setAsyncEventQueueIds(String[] asyncEventQueueIds) {
|
||||
this.asyncEventQueueIds = asyncEventQueueIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link RegionAttributes} used to configure this {@link Region}.
|
||||
*
|
||||
@@ -760,8 +800,10 @@ public abstract class PeerRegionFactoryBean<K, V> extends ConfigurableRegionFact
|
||||
* @see org.apache.geode.cache.DataPolicy
|
||||
*/
|
||||
public DataPolicy getDataPolicy() {
|
||||
return Optional.ofNullable(this.dataPolicy)
|
||||
.orElseThrow(() -> newIllegalStateException("Data Policy has not been properly resolved yet"));
|
||||
|
||||
Assert.state(this.dataPolicy != null, "Data Policy has not been properly resolved yet");
|
||||
|
||||
return this.dataPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -775,8 +817,6 @@ public abstract class PeerRegionFactoryBean<K, V> extends ConfigurableRegionFact
|
||||
this.diskStoreName = diskStoreName;
|
||||
}
|
||||
|
||||
// TODO: review/add Javadoc from here forward...
|
||||
|
||||
public void setEntryIdleTimeout(ExpirationAttributes entryIdleTimeout) {
|
||||
this.entryIdleTimeout = entryIdleTimeout;
|
||||
}
|
||||
@@ -801,6 +841,10 @@ public abstract class PeerRegionFactoryBean<K, V> extends ConfigurableRegionFact
|
||||
this.gatewaySenders = gatewaySenders;
|
||||
}
|
||||
|
||||
public void setGatewaySenderIds(String[] gatewaySenderIds) {
|
||||
this.gatewaySenderIds = gatewaySenderIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures whether to enable this {@link Region} with the ability to store data in {@literal off-heap memory}.
|
||||
*
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.xml;
|
||||
|
||||
import java.util.HashMap;
|
||||
@@ -23,8 +22,7 @@ import java.util.Optional;
|
||||
|
||||
import org.apache.geode.cache.asyncqueue.AsyncEventQueue;
|
||||
import org.apache.geode.cache.wan.GatewaySender;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.beans.PropertyValue;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
@@ -37,6 +35,9 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
@@ -107,10 +108,10 @@ abstract class AbstractRegionParser extends AbstractSingleBeanDefinitionParser {
|
||||
|
||||
mergeRegionTemplateAttributes(element, parserContext, regionBuilder, regionAttributesBuilder);
|
||||
|
||||
String resolvedCacheRef = ParsingUtils.resolveCacheReference(element.getAttribute("cache-ref"));
|
||||
String resolvedCacheReference = ParsingUtils.resolveCacheReference(element.getAttribute("cache-ref"));
|
||||
|
||||
if (!subRegion) {
|
||||
regionBuilder.addPropertyReference("cache", resolvedCacheRef);
|
||||
regionBuilder.addPropertyReference("cache", resolvedCacheReference);
|
||||
ParsingUtils.setPropertyValue(element, regionBuilder, "close");
|
||||
ParsingUtils.setPropertyValue(element, regionBuilder, "destroy");
|
||||
}
|
||||
@@ -158,7 +159,7 @@ abstract class AbstractRegionParser extends AbstractSingleBeanDefinitionParser {
|
||||
}
|
||||
|
||||
if (!subRegion) {
|
||||
parseSubRegions(element, parserContext, resolvedCacheRef);
|
||||
parseSubRegions(element, parserContext, resolvedCacheReference);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,7 +256,7 @@ abstract class AbstractRegionParser extends AbstractSingleBeanDefinitionParser {
|
||||
|
||||
String name = element.getAttribute(NAME_ATTRIBUTE);
|
||||
|
||||
return (StringUtils.hasText(name) ? name : element.getAttribute(ID_ATTRIBUTE));
|
||||
return StringUtils.hasText(name) ? name : element.getAttribute(ID_ATTRIBUTE);
|
||||
}
|
||||
|
||||
private String buildSubRegionPath(String parentName, String regionName) {
|
||||
@@ -269,7 +270,6 @@ abstract class AbstractRegionParser extends AbstractSingleBeanDefinitionParser {
|
||||
return regionPath;
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
private BeanDefinition parseSubRegion(Element element, ParserContext parserContext, String subRegionPath,
|
||||
String cacheRef) {
|
||||
|
||||
@@ -288,7 +288,6 @@ abstract class AbstractRegionParser extends AbstractSingleBeanDefinitionParser {
|
||||
return beanDefinition;
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
private String getParentRegionPathFrom(String regionPath) {
|
||||
|
||||
int index = regionPath.lastIndexOf("/");
|
||||
@@ -302,13 +301,14 @@ abstract class AbstractRegionParser extends AbstractSingleBeanDefinitionParser {
|
||||
return parentPath;
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
protected void validateDataPolicyShortcutAttributesMutualExclusion(Element element, ParserContext parserContext) {
|
||||
|
||||
if (element.hasAttribute("data-policy") && element.hasAttribute("shortcut")) {
|
||||
parserContext.getReaderContext().error(String.format(
|
||||
"Only one of [data-policy, shortcut] may be specified with element '%1$s'.", element.getTagName()),
|
||||
element);
|
||||
|
||||
String message = String.format("Only one of [data-policy, shortcut] may be specified with element [%s]",
|
||||
element.getTagName());
|
||||
|
||||
parserContext.getReaderContext().error(message, element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,6 +123,7 @@ abstract class ParsingUtils {
|
||||
static Object getBeanReference(Element element, ParserContext parserContext, String refAttributeName) {
|
||||
|
||||
String refAttributeValue = element.getAttribute(refAttributeName);
|
||||
Object returnValue = null;
|
||||
|
||||
if (StringUtils.hasText(refAttributeValue)) {
|
||||
if (!DomUtils.getChildElements(element).isEmpty()) {
|
||||
@@ -134,10 +135,10 @@ abstract class ParsingUtils {
|
||||
parserContext.getReaderContext().error(message, element);
|
||||
}
|
||||
|
||||
return null;
|
||||
returnValue = new RuntimeBeanReference(refAttributeValue);
|
||||
}
|
||||
|
||||
return new RuntimeBeanReference(refAttributeValue);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
static Object parseRefOrNestedCustomElement(Element element, ParserContext parserContext,
|
||||
@@ -377,11 +378,13 @@ abstract class ParsingUtils {
|
||||
static void parseOptionalRegionAttributes(Element element, ParserContext parserContext,
|
||||
BeanDefinitionBuilder regionAttributesBuilder) {
|
||||
|
||||
setPropertyValue(element, regionAttributesBuilder, "async-event-queue-ids");
|
||||
setPropertyValue(element, regionAttributesBuilder, "cloning-enabled");
|
||||
setPropertyValue(element, regionAttributesBuilder, "concurrency-level");
|
||||
setPropertyValue(element, regionAttributesBuilder, "disk-synchronous");
|
||||
setPropertyValue(element, regionAttributesBuilder, "enable-async-conflation");
|
||||
setPropertyValue(element, regionAttributesBuilder, "enable-subscription-conflation");
|
||||
setPropertyValue(element, regionAttributesBuilder, "gateway-sender-ids");
|
||||
setPropertyValue(element, regionAttributesBuilder, "ignore-jta", "ignoreJTA");
|
||||
setPropertyValue(element, regionAttributesBuilder, "index-update-type");
|
||||
setPropertyValue(element, regionAttributesBuilder, "initial-capacity");
|
||||
|
||||
@@ -626,6 +626,15 @@ use inner bean declarations.
|
||||
</xsd:choice>
|
||||
<xsd:group ref="subRegionGroup" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="async-event-queue-ids" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Comma-delimited list of Apache Geode, AsyncEventQueue (AEQ) IDs configured for this Region. This attribute is used
|
||||
when the member of the cluster hosting this Region is not the primary or secondary for the AEQ. If the member is
|
||||
primary or a secondary, then the nested async-event-queue or the async-event-queue-ref element should be declared instead.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="cloning-enabled" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[[
|
||||
@@ -641,6 +650,16 @@ in the cache. GemFire default is false.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="gateway-sender-ids" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Comma-delimited list of Apache Geode, GatewaySender IDs configured for this Region. This attribute is used
|
||||
when the member of the cluster hosting this Region is not the primary or secondary for the GatewaySender.
|
||||
If the member is primary or a secondary, then the nested gateway-sender or the gateway-sender-ref element
|
||||
should be declared instead.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
@@ -1050,6 +1069,34 @@ use inner bean declarations.
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="async-event-queue-ids" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Comma-delimited list of Apache Geode, AsyncEventQueue (AEQ) IDs configured for this Region. This attribute is used
|
||||
when the member of the cluster hosting this Region is not the primary or secondary for the AEQ. If the member is
|
||||
primary or a secondary, then the nested async-event-queue or the async-event-queue-ref element should be declared instead.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="gateway-sender-ids" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Comma-delimited list of Apache Geode, GatewaySender IDs configured for this Region. This attribute is used
|
||||
when the member of the cluster hosting this Region is not the primary or secondary for the GatewaySender.
|
||||
If the member is primary or a secondary, then the nested gateway-sender or the gateway-sender-ref element
|
||||
should be declared instead.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="ignore-jta" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Indicates whether operations on this Region participates in active JTA transactions or ignores them and operates
|
||||
outside of transactions. This is primarily used in cache loaders, writers, and listeners that need to perform
|
||||
non-transactional operations on a Region, such as caching a result set. GemFire default is false.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="index-update-type" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
|
||||
@@ -626,6 +626,15 @@ use inner bean declarations.
|
||||
</xsd:choice>
|
||||
<xsd:group ref="subRegionGroup" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="async-event-queue-ids" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Comma-delimited list of Apache Geode, AsyncEventQueue (AEQ) IDs configured for this Region. This attribute is used
|
||||
when the member of the cluster hosting this Region is not the primary or secondary for the AEQ. If the member is
|
||||
primary or a secondary, then the nested async-event-queue or the async-event-queue-ref element should be declared instead.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="cloning-enabled" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[[
|
||||
@@ -641,6 +650,16 @@ in the cache. GemFire default is false.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="gateway-sender-ids" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Comma-delimited list of Apache Geode, GatewaySender IDs configured for this Region. This attribute is used
|
||||
when the member of the cluster hosting this Region is not the primary or secondary for the GatewaySender.
|
||||
If the member is primary or a secondary, then the nested gateway-sender or the gateway-sender-ref element
|
||||
should be declared instead.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
@@ -1050,6 +1069,34 @@ use inner bean declarations.
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="async-event-queue-ids" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Comma-delimited list of Apache Geode, AsyncEventQueue (AEQ) IDs configured for this Region. This attribute is used
|
||||
when the member of the cluster hosting this Region is not the primary or secondary for the AEQ. If the member is
|
||||
primary or a secondary, then the nested async-event-queue or the async-event-queue-ref element should be declared instead.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="gateway-sender-ids" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Comma-delimited list of Apache Geode, GatewaySender IDs configured for this Region. This attribute is used
|
||||
when the member of the cluster hosting this Region is not the primary or secondary for the GatewaySender.
|
||||
If the member is primary or a secondary, then the nested gateway-sender or the gateway-sender-ref element
|
||||
should be declared instead.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="ignore-jta" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Indicates whether operations on this Region participates in active JTA transactions or ignores them and operates
|
||||
outside of transactions. This is primarily used in cache loaders, writers, and listeners that need to perform
|
||||
non-transactional operations on a Region, such as caching a result set. GemFire default is false.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="index-update-type" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
|
||||
@@ -13,13 +13,12 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.xml;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Matchers.isNull;
|
||||
import static org.mockito.Matchers.matches;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.isNull;
|
||||
import static org.mockito.ArgumentMatchers.matches;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
@@ -29,9 +28,11 @@ import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.xml.XmlReaderContext;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
@@ -50,15 +51,20 @@ public class AbstractRegionParserUnitTests {
|
||||
private AbstractRegionParser regionParser = new TestRegionParser();
|
||||
|
||||
protected void assertIsRegionTemplateWhenElementLocalNameEndsWithTemplate(String localName) {
|
||||
|
||||
Element mockElement = mock(Element.class);
|
||||
|
||||
when(mockElement.getLocalName()).thenReturn(localName);
|
||||
|
||||
assertThat(regionParser.isRegionTemplate(mockElement)).isEqualTo(nullSafeEndsWith(localName, "-template"));
|
||||
|
||||
verify(mockElement, times(1)).getLocalName();
|
||||
}
|
||||
|
||||
protected void assertIsSubRegionWhenElementLocalNameEndsWithRegion(String localName) {
|
||||
|
||||
Element mockElement = mock(Element.class);
|
||||
|
||||
Node mockNode = mock(Node.class);
|
||||
|
||||
when(mockElement.getParentNode()).thenReturn(mockNode);
|
||||
@@ -71,12 +77,14 @@ public class AbstractRegionParserUnitTests {
|
||||
}
|
||||
|
||||
protected boolean nullSafeEndsWith(String localName, String suffix) {
|
||||
return (localName != null && localName.endsWith(suffix));
|
||||
return localName != null && localName.endsWith(suffix);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getBeanClassIsEqualToTestRegionFactoryBean() {
|
||||
|
||||
AbstractRegionParser regionParserSpy = spy(AbstractRegionParser.class);
|
||||
|
||||
Element mockElement = mock(Element.class);
|
||||
|
||||
doReturn(AbstractRegionParserUnitTests.class).when(regionParserSpy).getRegionFactoryClass();
|
||||
@@ -89,24 +97,31 @@ public class AbstractRegionParserUnitTests {
|
||||
|
||||
@Test
|
||||
public void getParentNameWhenTemplateIsSet() {
|
||||
|
||||
Element mockElement = mock(Element.class);
|
||||
|
||||
when(mockElement.getAttribute(eq("template"))).thenReturn("test");
|
||||
|
||||
assertThat(regionParser.getParentName(mockElement)).isEqualTo("test");
|
||||
|
||||
verify(mockElement, times(1)).getAttribute(eq("template"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getParentNameWhenTemplateIsUnset() {
|
||||
|
||||
Element mockElement = mock(Element.class);
|
||||
|
||||
when(mockElement.getAttribute(eq("template"))).thenReturn(null);
|
||||
|
||||
assertThat(regionParser.getParentName(mockElement)).isNull();
|
||||
|
||||
verify(mockElement, times(1)).getAttribute(eq("template"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isRegionTemplateWithRegionTemplateElementsIsTrue() {
|
||||
|
||||
assertIsRegionTemplateWhenElementLocalNameEndsWithTemplate("client-region-template");
|
||||
assertIsRegionTemplateWhenElementLocalNameEndsWithTemplate("local-region-template");
|
||||
assertIsRegionTemplateWhenElementLocalNameEndsWithTemplate("partitioned-region-template");
|
||||
@@ -115,6 +130,7 @@ public class AbstractRegionParserUnitTests {
|
||||
|
||||
@Test
|
||||
public void isRegionTemplateWithRegionElementsIsFalse() {
|
||||
|
||||
assertIsRegionTemplateWhenElementLocalNameEndsWithTemplate("client-region");
|
||||
assertIsRegionTemplateWhenElementLocalNameEndsWithTemplate("local-region");
|
||||
assertIsRegionTemplateWhenElementLocalNameEndsWithTemplate("partitioned-region");
|
||||
@@ -133,6 +149,7 @@ public class AbstractRegionParserUnitTests {
|
||||
|
||||
@Test
|
||||
public void isSubRegionWithRegionElementIsTrue() {
|
||||
|
||||
assertIsSubRegionWhenElementLocalNameEndsWithRegion("client-region");
|
||||
assertIsSubRegionWhenElementLocalNameEndsWithRegion("local-region");
|
||||
assertIsSubRegionWhenElementLocalNameEndsWithRegion("partitioned-region");
|
||||
@@ -141,6 +158,7 @@ public class AbstractRegionParserUnitTests {
|
||||
|
||||
@Test
|
||||
public void isSubRegionWithRegionTemplateElementIsFalse() {
|
||||
|
||||
assertIsSubRegionWhenElementLocalNameEndsWithRegion("client-region-template");
|
||||
assertIsSubRegionWhenElementLocalNameEndsWithRegion("local-region-template");
|
||||
assertIsSubRegionWhenElementLocalNameEndsWithRegion("partitioned-region-template");
|
||||
@@ -160,11 +178,13 @@ public class AbstractRegionParserUnitTests {
|
||||
|
||||
@Test
|
||||
public void doParseWithAbstractRegionTemplate() {
|
||||
|
||||
AbstractRegionParser regionParserSpy = spy(AbstractRegionParser.class);
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
|
||||
|
||||
Element mockElement = mock(Element.class);
|
||||
|
||||
Node mockNode = mock(Node.class);
|
||||
|
||||
when(mockElement.getLocalName()).thenReturn("partitioned-region-template");
|
||||
@@ -175,13 +195,14 @@ public class AbstractRegionParserUnitTests {
|
||||
|
||||
assertThat(builder.getRawBeanDefinition().isAbstract()).isTrue();
|
||||
|
||||
verify(regionParserSpy, times(1)).doParse(eq(mockElement), isNull(ParserContext.class), eq(builder));
|
||||
verify(regionParserSpy, times(1)).doParseRegion(eq(mockElement), isNull(ParserContext.class),
|
||||
verify(regionParserSpy, times(1)).doParse(eq(mockElement), isNull(), eq(builder));
|
||||
verify(regionParserSpy, times(1)).doParseRegion(eq(mockElement), isNull(),
|
||||
eq(builder), eq(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doParseWithNonAbstractSubRegion() {
|
||||
|
||||
AbstractRegionParser regionParserSpy = spy(AbstractRegionParser.class);
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
|
||||
@@ -197,19 +218,20 @@ public class AbstractRegionParserUnitTests {
|
||||
|
||||
assertThat(builder.getRawBeanDefinition().isAbstract()).isFalse();
|
||||
|
||||
verify(regionParserSpy, times(1)).doParse(eq(mockElement), isNull(ParserContext.class), eq(builder));
|
||||
verify(regionParserSpy, times(1)).doParseRegion(eq(mockElement), isNull(ParserContext.class),
|
||||
verify(regionParserSpy, times(1)).doParse(eq(mockElement), isNull(), eq(builder));
|
||||
verify(regionParserSpy, times(1)).doParseRegion(eq(mockElement), isNull(),
|
||||
eq(builder), eq(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateDataPolicyShortcutAttributesMutualExclusion() {
|
||||
|
||||
Element mockElement = mock(Element.class);
|
||||
|
||||
when(mockElement.hasAttribute(matches("data-policy"))).thenReturn(false);
|
||||
when(mockElement.hasAttribute(matches("shortcut"))).thenReturn(false);
|
||||
|
||||
regionParser.validateDataPolicyShortcutAttributesMutualExclusion(mockElement, null);
|
||||
this.regionParser.validateDataPolicyShortcutAttributesMutualExclusion(mockElement, null);
|
||||
|
||||
verify(mockElement).hasAttribute(eq("data-policy"));
|
||||
verify(mockElement, never()).hasAttribute(eq("shortcut"));
|
||||
@@ -217,12 +239,13 @@ public class AbstractRegionParserUnitTests {
|
||||
|
||||
@Test
|
||||
public void validateDataPolicyShortcutAttributesMutualExclusionWithDataPolicy() {
|
||||
|
||||
Element mockElement = mock(Element.class);
|
||||
|
||||
when(mockElement.hasAttribute(matches("data-policy"))).thenReturn(true);
|
||||
when(mockElement.hasAttribute(matches("shortcut"))).thenReturn(false);
|
||||
|
||||
regionParser.validateDataPolicyShortcutAttributesMutualExclusion(mockElement, null);
|
||||
this.regionParser.validateDataPolicyShortcutAttributesMutualExclusion(mockElement, null);
|
||||
|
||||
verify(mockElement).hasAttribute(eq("data-policy"));
|
||||
verify(mockElement).hasAttribute(eq("shortcut"));
|
||||
@@ -230,12 +253,13 @@ public class AbstractRegionParserUnitTests {
|
||||
|
||||
@Test
|
||||
public void validateDataPolicyShortcutAttributesMutualExclusionWithShortcut() {
|
||||
|
||||
Element mockElement = mock(Element.class);
|
||||
|
||||
when(mockElement.hasAttribute(matches("data-policy"))).thenReturn(false);
|
||||
when(mockElement.hasAttribute(matches("shortcut"))).thenReturn(true);
|
||||
|
||||
regionParser.validateDataPolicyShortcutAttributesMutualExclusion(mockElement, null);
|
||||
this.regionParser.validateDataPolicyShortcutAttributesMutualExclusion(mockElement, null);
|
||||
|
||||
verify(mockElement).hasAttribute(eq("data-policy"));
|
||||
verify(mockElement, never()).hasAttribute(eq("shortcut"));
|
||||
@@ -243,7 +267,9 @@ public class AbstractRegionParserUnitTests {
|
||||
|
||||
@Test
|
||||
public void validateDataPolicyShortcutAttributesMutualExclusionWithDataPolicyAndShortcut() {
|
||||
|
||||
Element mockElement = mock(Element.class);
|
||||
|
||||
XmlReaderContext mockReaderContext = mock(XmlReaderContext.class);
|
||||
|
||||
ParserContext mockParserContext = new ParserContext(mockReaderContext, null);
|
||||
@@ -252,10 +278,10 @@ public class AbstractRegionParserUnitTests {
|
||||
when(mockElement.hasAttribute(matches("shortcut"))).thenReturn(true);
|
||||
when(mockElement.getTagName()).thenReturn("local-region");
|
||||
|
||||
regionParser.validateDataPolicyShortcutAttributesMutualExclusion(mockElement, mockParserContext);
|
||||
this.regionParser.validateDataPolicyShortcutAttributesMutualExclusion(mockElement, mockParserContext);
|
||||
|
||||
verify(mockReaderContext).error(
|
||||
eq("Only one of [data-policy, shortcut] may be specified with element 'local-region'."),
|
||||
eq("Only one of [data-policy, shortcut] may be specified with element [local-region]"),
|
||||
eq(mockElement));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user